From 7722b3d09721532bc91c94e2cac2d909f93a6336 Mon Sep 17 00:00:00 2001
From: Albert Noll
Date: Mon, 3 Mar 2014 08:04:14 +0100
Subject: [PATCH 001/116] 8035946: Use ResourceHashtable for dependency
checking
Use ResourceHashtable for dependency checking and delete GenericHashtable
Reviewed-by: kvn, coleenp
---
hotspot/src/share/vm/code/dependencies.cpp | 8 +-
hotspot/src/share/vm/code/dependencies.hpp | 7 +-
hotspot/src/share/vm/code/nmethod.cpp | 14 ++-
hotspot/src/share/vm/utilities/hashtable.cpp | 113 ------------------
hotspot/src/share/vm/utilities/hashtable.hpp | 82 -------------
.../src/share/vm/utilities/resourceHash.hpp | 10 +-
6 files changed, 26 insertions(+), 208 deletions(-)
diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp
index d3dcf5da9a6..bee31fcacfc 100644
--- a/hotspot/src/share/vm/code/dependencies.cpp
+++ b/hotspot/src/share/vm/code/dependencies.cpp
@@ -725,13 +725,13 @@ Klass* Dependencies::DepStream::context_type() {
}
// ----------------- DependencySignature --------------------------------------
-bool DependencySignature::equals(DependencySignature* sig) const {
- if ((type() != sig->type()) || (args_count() != sig->args_count())) {
+bool DependencySignature::equals(DependencySignature const& s1, DependencySignature const& s2) {
+ if ((s1.type() != s2.type()) || (s1.args_count() != s2.args_count())) {
return false;
}
- for (int i = 0; i < sig->args_count(); i++) {
- if (arg(i) != sig->arg(i)) {
+ for (int i = 0; i < s1.args_count(); i++) {
+ if (s1.arg(i) != s2.arg(i)) {
return false;
}
}
diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp
index 050478cbc85..3501b57fd51 100644
--- a/hotspot/src/share/vm/code/dependencies.hpp
+++ b/hotspot/src/share/vm/code/dependencies.hpp
@@ -527,7 +527,7 @@ class Dependencies: public ResourceObj {
};
-class DependencySignature : public GenericHashtableEntry {
+class DependencySignature : public ResourceObj {
private:
int _args_count;
uintptr_t _argument_hash[Dependencies::max_arg_count];
@@ -542,12 +542,13 @@ class DependencySignature : public GenericHashtableEntry> 2; }
+ static bool equals(DependencySignature const& s1, DependencySignature const& s2);
+ static unsigned hash (DependencySignature const& s1) { return s1.arg(0) >> 2; }
int args_count() const { return _args_count; }
uintptr_t arg(int idx) const { return _argument_hash[idx]; }
Dependencies::DepType type() const { return _type; }
+
};
diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp
index 020916b8d34..a002ee76ea4 100644
--- a/hotspot/src/share/vm/code/nmethod.cpp
+++ b/hotspot/src/share/vm/code/nmethod.cpp
@@ -39,6 +39,7 @@
#include "prims/jvmtiImpl.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/sweeper.hpp"
+#include "utilities/resourceHash.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/xmlstream.hpp"
@@ -2135,7 +2136,11 @@ void nmethod::check_all_dependencies(DepChange& changes) {
// Turn off dependency tracing while actually testing dependencies.
NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) );
- GenericHashtable* table = new GenericHashtable(11027);
+ typedef ResourceHashtable DepTable;
+
+ DepTable* table = new DepTable();
+
// Iterate over live nmethods and check dependencies of all nmethods that are not
// marked for deoptimization. A particular dependency is only checked once.
for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) {
@@ -2143,9 +2148,10 @@ void nmethod::check_all_dependencies(DepChange& changes) {
for (Dependencies::DepStream deps(nm); deps.next(); ) {
// Construct abstraction of a dependency.
DependencySignature* current_sig = new DependencySignature(deps);
- // Determine if 'deps' is already checked. table->add() returns
- // 'true' if the dependency was added (i.e., was not in the hashtable).
- if (table->add(current_sig)) {
+
+ // Determine if dependency is already checked. table->put(...) returns
+ // 'true' if the dependency is added (i.e., was not in the hashtable).
+ if (table->put(*current_sig, 1)) {
if (deps.check_dependency() != NULL) {
// Dependency checking failed. Print out information about the failed
// dependency and finally fail with an assert. We can fail here, since
diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp
index a850ebe87f4..8698cca914a 100644
--- a/hotspot/src/share/vm/utilities/hashtable.cpp
+++ b/hotspot/src/share/vm/utilities/hashtable.cpp
@@ -25,7 +25,6 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp"
-#include "code/dependencies.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "memory/resourceArea.hpp"
@@ -353,116 +352,6 @@ template void BasicHashtable::verify_lookup_length(double load)
#endif
-template GenericHashtable::GenericHashtable(int size, bool C_heap, MEMFLAGS memflag) {
- assert(size > 0, " Invalid hashtable size");
- _size = size;
- _C_heap = C_heap;
- _memflag = memflag;
- // Perform subtype-specific resource allocation
- _items = (C_heap) ? NEW_C_HEAP_ARRAY(T*, size, memflag) : NEW_RESOURCE_ARRAY(T*, size);
- memset(_items, 0, sizeof(T*) * size);
-
- DEBUG_ONLY(_num_items = 0;)
-}
-
-template GenericHashtable::~GenericHashtable() {
- if (on_C_heap()) {
- // Check backing array
- for (int i = 0; i < size(); i++) {
- T* item = head(i);
- // Delete all items in linked list
- while (item != NULL) {
- T* next_item = item->next();
- delete item;
- DEBUG_ONLY(_num_items--);
- item = next_item;
- }
- }
- FREE_C_HEAP_ARRAY(T*, _items, _memflag);
- _items = NULL;
- assert (_num_items == 0, "Not all memory released");
- }
-}
-
-/**
- * Return a pointer to the item 'I' that is stored in the hashtable for
- * which match_item->equals(I) == true. If no such item is found, NULL
- * is returned.
- */
-template T* GenericHashtable::contains(T* match_item) {
- if (match_item != NULL) {
- int idx = index(match_item);
- return contains_impl(match_item, idx);
- }
- return NULL;
-}
-
-/**
- * Add item to the hashtable. Return 'true' if the item was added
- * and false otherwise.
- */
-template bool GenericHashtable::add(T* item) {
- if (item != NULL) {
- int idx = index(item);
- T* found_item = contains_impl(item, idx);
- if (found_item == NULL) {
- T* list_head = head(idx);
- item->set_next(list_head);
- item->set_prev(NULL);
-
- if (list_head != NULL) {
- list_head->set_prev(item);
- }
- set_head(item, idx);
- DEBUG_ONLY(_num_items++);
- return true;
- }
- }
- return false;
-}
-
-/**
- * Removes an item 'I' from the hashtable, if present. 'I' is removed, if
- * match_item->equals(I) == true. Removing an item from the hashtable does
- * not free memory.
- */
-template T* GenericHashtable::remove(T* match_item) {
- if (match_item != NULL) {
- int idx = index(match_item);
- T* found_item = contains_impl(match_item, idx);
- if (found_item != NULL) {
- // Remove item from linked list
- T* prev = found_item->prev();
- T* next = found_item->next();
- if (prev != NULL) {
- prev->set_next(next);
- } else {
- set_head(next, idx);
- }
- if (next != NULL) {
- next->set_prev(prev);
- }
-
- DEBUG_ONLY(_num_items--);
- return found_item;
- }
- }
- return NULL;
-}
-
-
-template T* GenericHashtable::contains_impl(T* item, int idx) {
- T* current_item = head(idx);
- while (current_item != NULL) {
- if (current_item->equals(item)) {
- return current_item;
- }
- current_item = current_item->next();
- }
- return NULL;
-}
-
-
// Explicitly instantiate these types
template class Hashtable;
template class Hashtable;
@@ -482,5 +371,3 @@ template class BasicHashtable;
template class BasicHashtable;
template class BasicHashtable;
template class BasicHashtable;
-
-template class GenericHashtable;
diff --git a/hotspot/src/share/vm/utilities/hashtable.hpp b/hotspot/src/share/vm/utilities/hashtable.hpp
index 8294eaab3d2..fcebf72ea95 100644
--- a/hotspot/src/share/vm/utilities/hashtable.hpp
+++ b/hotspot/src/share/vm/utilities/hashtable.hpp
@@ -327,86 +327,4 @@ public:
}
};
-
-/*
- * Usage of GenericHashtable:
- *
- * class X : public GenericHashtableEntry {
- *
- * // Implement virtual functions in class X
- * bool equals(X* sig) const;
- * uintptr_t hash() const;
- * };
- *
- * void foo() {
- * GenericHashtable* table = new GenericHashtable(11027, false);
- *
- * X* elem = new X();
- * table->add(elem);
- * table->contains(elem);
- * }
- *
- * You can choose other allocation types as well. For example, to store the hashtable to a
- * particular region (CHeapObj) simply replace ResourceObj with the desired type:
- *
- * class X : public GenericHashtableEntry > { ... };
- *
- * To make the destructor (and remove) of the hashtable work:
- * 1) override the delete operator of X
- * 2) provide a destructor of the X
- *
- * You may also find it convenient to override the new operator.
- *
- * If you use this templates do not forget to add an explicit initialization
- * (at the end of hashtable.cpp).
- *
- * template class GenericHashtable;
- */
-template class GenericHashtableEntry : public M {
- private:
- T* _next;
- T* _prev;
- public:
- // Must be implemented by subclass.
- virtual uintptr_t key() const = 0;
- virtual bool equals(T* other) const = 0;
-
- T* next() const { return _next; }
- T* prev() const { return _prev; }
- void set_next(T* item) { _next = item; }
- void set_prev(T* item) { _prev = item; }
-
- // Constructor and destructor
- GenericHashtableEntry() : _next(NULL), _prev(NULL) { };
- virtual ~GenericHashtableEntry() {};
-};
-
-template class GenericHashtable : public M {
- private:
- T** _items;
- int _size;
- bool _C_heap;
- MEMFLAGS _memflag;
-
- // Accessor methods
- T* head (int idx) const { return _items[idx]; }
- void set_head(T* item, int idx) { _items[idx] = item; }
- int index (T* item) { assert(item != NULL, "missing null check"); return item->key() % size(); }
-
- // Helper function
- T* contains_impl(T* item, int idx);
-
- DEBUG_ONLY(int _num_items;)
- public:
- GenericHashtable(int size, bool C_heap = false, MEMFLAGS memflag = mtNone);
- ~GenericHashtable();
- T* contains(T* match_item);
- T* remove (T* match_item);
- bool add (T* item);
-
-
- bool on_C_heap() const { return _C_heap; }
- int size() const { return _size; }
-};
-
#endif // SHARE_VM_UTILITIES_HASHTABLE_HPP
diff --git a/hotspot/src/share/vm/utilities/resourceHash.hpp b/hotspot/src/share/vm/utilities/resourceHash.hpp
index 2fe5dec941a..211d6bca117 100644
--- a/hotspot/src/share/vm/utilities/resourceHash.hpp
+++ b/hotspot/src/share/vm/utilities/resourceHash.hpp
@@ -105,14 +105,20 @@ class ResourceHashtable : public ResourceObj {
}
}
- // Inserts or replaces a value in the table
- void put(K const& key, V const& value) {
+ /**
+ * Inserts or replaces a value in the table.
+ * @return: true: if a new item is added
+ * false: if the item already existed and the value is updated
+ */
+ bool put(K const& key, V const& value) {
unsigned hv = HASH(key);
Node** ptr = lookup_node(hv, key);
if (*ptr != NULL) {
(*ptr)->_value = value;
+ return false;
} else {
*ptr = new Node(hv, key, value);
+ return true;
}
}
From 0b6a5f744ab3e4699a626396f1950855154b6921 Mon Sep 17 00:00:00 2001
From: Nils Eliasson
Date: Tue, 28 Jan 2014 15:05:46 +0100
Subject: [PATCH 002/116] 8007270: Make IsMethodCompilable test work with
tiered
Only c2 compiles counts toward cutoff
Reviewed-by: kvn, roland
---
.../whitebox/CompilerWhiteBoxTest.java | 23 ++++++
.../whitebox/IsMethodCompilableTest.java | 71 +++++++++++--------
.../com/oracle/java/testlibrary/Platform.java | 9 +++
3 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
index e47231e29f5..97dad5bf704 100644
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
@@ -195,6 +195,29 @@ public abstract class CompilerWhiteBoxTest {
printInfo();
}
+ /**
+ * Checks, that {@linkplain #method} is not compiled at the given compilation
+ * level or above.
+ *
+ * @param compLevel
+ *
+ * @throws RuntimeException if {@linkplain #method} is in compiler queue or
+ * is compiled, or if {@linkplain #method} has zero
+ * compilation level.
+ */
+
+ protected final void checkNotCompiled(int compLevel) {
+ if (WHITE_BOX.isMethodQueuedForCompilation(method)) {
+ throw new RuntimeException(method + " must not be in queue");
+ }
+ if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) {
+ throw new RuntimeException(method + " comp_level must be >= maxCompLevel");
+ }
+ if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) {
+ throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel");
+ }
+ }
+
/**
* Checks, that {@linkplain #method} is not compiled.
*
diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
index bd5916a7ca8..83d88669735 100644
--- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
+++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
@@ -24,13 +24,17 @@
/*
* @test IsMethodCompilableTest
* @bug 8007270 8006683 8007288 8022832
- * @library /testlibrary /testlibrary/whitebox
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/com/oracle/java/testlibrary
* @build IsMethodCompilableTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
- * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
+ * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
+ * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
* @summary testing of WB::isMethodCompilable()
* @author igor.ignatyev@oracle.com
*/
+
+import com.oracle.java.testlibrary.Platform;
+
public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
/**
* Value of {@code -XX:PerMethodRecompilationCutoff}
@@ -43,7 +47,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
if (tmp == -1) {
PER_METHOD_RECOMPILATION_CUTOFF = -1 /* Inf */;
} else {
- PER_METHOD_RECOMPILATION_CUTOFF = 1 + (0xFFFFFFFFL & tmp);
+ PER_METHOD_RECOMPILATION_CUTOFF = (0xFFFFFFFFL & tmp);
}
}
@@ -60,19 +64,26 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
/**
* Tests {@code WB::isMethodCompilable()} by recompilation of tested method
* 'PerMethodRecompilationCutoff' times and checks compilation status. Also
- * checks that WB::clearMethodState() clears no-compilable flags.
+ * checks that WB::clearMethodState() clears no-compilable flags. Only
+ * applicable to c2 compiled methods.
*
* @throws Exception if one of the checks fails.
*/
@Override
protected void test() throws Exception {
+
+ // Only c2 compilations can be disabled through PerMethodRecompilationCutoff
+ if (!Platform.isServer()) {
+ return;
+ }
+
if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
"compiled ")) {
- System.err.printf("Warning: %s is not applicable in %s%n",
- testCase.name(), CompilerWhiteBoxTest.MODE);
- return;
+ System.err.printf("Warning: %s is not applicable in %s%n",
+ testCase.name(), CompilerWhiteBoxTest.MODE);
+ return;
}
- if (!isCompilable()) {
+ if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
throw new RuntimeException(method + " must be compilable");
}
System.out.println("PerMethodRecompilationCutoff = "
@@ -83,39 +94,37 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
return;
}
- // deoptimize 'PerMethodRecompilationCutoff' times and clear state
- for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) {
- compileAndDeoptimize();
+ // deoptimize 'PerMethodRecompilationCutoff' times
+ for (long attempts = 0, successes = 0;
+ (successes < PER_METHOD_RECOMPILATION_CUTOFF) &&
+ (attempts < PER_METHOD_RECOMPILATION_CUTOFF*2) &&
+ isCompilable(COMP_LEVEL_FULL_OPTIMIZATION); attempts++) {
+ if (compileAndDeoptimize() == COMP_LEVEL_FULL_OPTIMIZATION) {
+ successes++;
+ }
}
- if (!testCase.isOsr() && !isCompilable()) {
- // in osr test case count of deopt maybe more than iterations
- throw new RuntimeException(method + " is not compilable after "
- + (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations");
- }
- WHITE_BOX.clearMethodState(method);
- // deoptimize 'PerMethodRecompilationCutoff' + 1 times
- long i;
- for (i = 0L; i < PER_METHOD_RECOMPILATION_CUTOFF
- && isCompilable(); ++i) {
- compileAndDeoptimize();
- }
- if (!testCase.isOsr() && i != PER_METHOD_RECOMPILATION_CUTOFF) {
+ if (!testCase.isOsr() && !isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
// in osr test case count of deopt maybe more than iterations
throw new RuntimeException(method + " is not compilable after "
- + i + " iterations, but must only after "
- + PER_METHOD_RECOMPILATION_CUTOFF);
+ + PER_METHOD_RECOMPILATION_CUTOFF + " iterations");
}
- if (isCompilable()) {
+
+ // Now compile once more
+ compileAndDeoptimize();
+
+ if (isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
throw new RuntimeException(method + " is still compilable after "
+ PER_METHOD_RECOMPILATION_CUTOFF + " iterations");
}
- compile();
checkNotCompiled();
+ compile();
+ waitBackgroundCompilation();
+ checkNotCompiled(COMP_LEVEL_FULL_OPTIMIZATION);
// WB.clearMethodState() must reset no-compilable flags
WHITE_BOX.clearMethodState(method);
- if (!isCompilable()) {
+ if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
throw new RuntimeException(method
+ " is not compilable after clearMethodState()");
}
@@ -123,9 +132,11 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
checkCompiled();
}
- private void compileAndDeoptimize() throws Exception {
+ private int compileAndDeoptimize() throws Exception {
compile();
waitBackgroundCompilation();
+ int compLevel = getCompLevel();
deoptimize();
+ return compLevel;
}
}
diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
index a2e5f82ad71..34b2f20f9a3 100644
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java
@@ -28,6 +28,15 @@ public class Platform {
private static final String dataModel = System.getProperty("sun.arch.data.model");
private static final String vmVersion = System.getProperty("java.vm.version");
private static final String osArch = System.getProperty("os.arch");
+ private static final String vmName = System.getProperty("java.vm.name");
+
+ public static boolean isClient() {
+ return vmName.endsWith(" Client VM");
+ }
+
+ public static boolean isServer() {
+ return vmName.endsWith(" Server VM");
+ }
public static boolean is32bit() {
return dataModel.equals("32");
From 4dde43fa62eacbace22d8123b89253c5831c7a82 Mon Sep 17 00:00:00 2001
From: Jesper Wilhelmsson
Date: Fri, 31 Jan 2014 13:38:01 +0100
Subject: [PATCH 003/116] 8023899: Typo in TraceCPUTime message
Removed the comma
Reviewed-by: pliden, tschatzl
---
hotspot/src/share/vm/runtime/timer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hotspot/src/share/vm/runtime/timer.cpp b/hotspot/src/share/vm/runtime/timer.cpp
index ccb3322cedd..e33a51cfb97 100644
--- a/hotspot/src/share/vm/runtime/timer.cpp
+++ b/hotspot/src/share/vm/runtime/timer.cpp
@@ -194,7 +194,7 @@ TraceCPUTime::~TraceCPUTime() {
system_secs = system_time - _starting_system_time;
real_secs = real_time - _starting_real_time;
- _logfile->print(" [Times: user=%3.2f sys=%3.2f, real=%3.2f secs] ",
+ _logfile->print(" [Times: user=%3.2f sys=%3.2f real=%3.2f secs] ",
user_secs, system_secs, real_secs);
} else {
From ce89103d32c6515e83e6564faad7eea076ce85ff Mon Sep 17 00:00:00 2001
From: Volker Simonis
Date: Mon, 10 Feb 2014 10:52:02 +0100
Subject: [PATCH 004/116] 8033951: nasgen needs the newly build nasgen and
nashorn classes in the bootclasspath
Reviewed-by: erikj
---
nashorn/make/BuildNashorn.gmk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nashorn/make/BuildNashorn.gmk b/nashorn/make/BuildNashorn.gmk
index fc87044245b..a987874c7ea 100644
--- a/nashorn/make/BuildNashorn.gmk
+++ b/nashorn/make/BuildNashorn.gmk
@@ -77,7 +77,7 @@ $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
$(RM) -rf $(@D)/jdk $(@D)/netscape
$(CP) -R -p $(NASHORN_OUTPUTDIR)/nashorn_classes/* $(@D)/
$(FIXPATH) $(JAVA) \
- -cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
+ -Xbootclasspath/p:"$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
$(TOUCH) $@
From d54998d0af7551223c20bba9be0a0d533067df01 Mon Sep 17 00:00:00 2001
From: Omair Majid
Date: Thu, 20 Feb 2014 10:07:46 -0500
Subject: [PATCH 005/116] 8035341: Allow using a system installed libpng
Reviewed-by: andrew, erikj, ihse, serb
---
common/autoconf/generated-configure.sh | 124 ++++++++++++++++++++++++-
common/autoconf/libraries.m4 | 40 ++++++++
common/autoconf/spec.gmk.in | 9 ++
3 files changed, 172 insertions(+), 1 deletion(-)
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 25db0b333ca..138c51adcfd 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -646,6 +646,9 @@ LIBDL
LIBM
LIBZIP_CAN_USE_MMAP
USE_EXTERNAL_LIBZ
+USE_EXTERNAL_LIBPNG
+PNG_LIBS
+PNG_CFLAGS
USE_EXTERNAL_LIBGIF
USE_EXTERNAL_LIBJPEG
ALSA_LIBS
@@ -1070,6 +1073,7 @@ with_alsa
with_alsa_include
with_alsa_lib
with_giflib
+with_libpng
with_zlib
with_stdc__lib
with_num_cores
@@ -1178,6 +1182,8 @@ FREETYPE_CFLAGS
FREETYPE_LIBS
ALSA_CFLAGS
ALSA_LIBS
+PNG_CFLAGS
+PNG_LIBS
LIBFFI_CFLAGS
LIBFFI_LIBS
CCACHE'
@@ -1921,6 +1927,8 @@ Optional Packages:
--with-alsa-lib specify directory for the alsa library
--with-giflib use giflib from build system or OpenJDK source
(system, bundled) [bundled]
+ --with-libpng use libpng from build system or OpenJDK source
+ (system, bundled) [bundled]
--with-zlib use zlib from build system or OpenJDK source
(system, bundled) [bundled]
--with-stdc++lib=,,
@@ -2037,6 +2045,8 @@ Some influential environment variables:
linker flags for FREETYPE, overriding pkg-config
ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config
ALSA_LIBS linker flags for ALSA, overriding pkg-config
+ PNG_CFLAGS C compiler flags for PNG, overriding pkg-config
+ PNG_LIBS linker flags for PNG, overriding pkg-config
LIBFFI_CFLAGS
C compiler flags for LIBFFI, overriding pkg-config
LIBFFI_LIBS linker flags for LIBFFI, overriding pkg-config
@@ -4092,7 +4102,7 @@ fi
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1392111785
+DATE_WHEN_GENERATED=1392907541
###############################################################################
#
@@ -47214,6 +47224,118 @@ fi
fi
+ ###############################################################################
+ #
+ # Check for the png library
+ #
+
+
+# Check whether --with-libpng was given.
+if test "${with_libpng+set}" = set; then :
+ withval=$with_libpng;
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for which libpng to use" >&5
+$as_echo_n "checking for which libpng to use... " >&6; }
+
+ # default is bundled
+ DEFAULT_LIBPNG=bundled
+
+ #
+ # if user didn't specify, use DEFAULT_LIBPNG
+ #
+ if test "x${with_libpng}" = "x"; then
+ with_libpng=${DEFAULT_LIBPNG}
+ fi
+
+ if test "x${with_libpng}" = "xbundled"; then
+ USE_EXTERNAL_LIBPNG=false
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
+$as_echo "bundled" >&6; }
+ elif test "x${with_libpng}" = "xsystem"; then
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG" >&5
+$as_echo_n "checking for PNG... " >&6; }
+
+if test -n "$PNG_CFLAGS"; then
+ pkg_cv_PNG_CFLAGS="$PNG_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libpng") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_PNG_CFLAGS=`$PKG_CONFIG --cflags "libpng" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$PNG_LIBS"; then
+ pkg_cv_PNG_LIBS="$PNG_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libpng\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libpng") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_PNG_LIBS=`$PKG_CONFIG --libs "libpng" 2>/dev/null`
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ PNG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "libpng" 2>&1`
+ else
+ PNG_PKG_ERRORS=`$PKG_CONFIG --print-errors "libpng" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$PNG_PKG_ERRORS" >&5
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ LIBPNG_FOUND=no
+elif test $pkg_failed = untried; then
+ LIBPNG_FOUND=no
+else
+ PNG_CFLAGS=$pkg_cv_PNG_CFLAGS
+ PNG_LIBS=$pkg_cv_PNG_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ LIBPNG_FOUND=yes
+fi
+ if test "x${LIBPNG_FOUND}" = "xyes"; then
+ USE_EXTERNAL_LIBPNG=true
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5
+$as_echo "system" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5
+$as_echo "system not found" >&6; }
+ as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5
+ fi
+ else
+ as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5
+ fi
+
+
###############################################################################
#
# Check for the zlib library
diff --git a/common/autoconf/libraries.m4 b/common/autoconf/libraries.m4
index dccec779cfc..9a187c5b3da 100644
--- a/common/autoconf/libraries.m4
+++ b/common/autoconf/libraries.m4
@@ -652,6 +652,46 @@ AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS],
fi
AC_SUBST(USE_EXTERNAL_LIBGIF)
+ ###############################################################################
+ #
+ # Check for the png library
+ #
+
+ AC_ARG_WITH(libpng, [AS_HELP_STRING([--with-libpng],
+ [use libpng from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])])
+
+
+ AC_MSG_CHECKING([for which libpng to use])
+
+ # default is bundled
+ DEFAULT_LIBPNG=bundled
+
+ #
+ # if user didn't specify, use DEFAULT_LIBPNG
+ #
+ if test "x${with_libpng}" = "x"; then
+ with_libpng=${DEFAULT_LIBPNG}
+ fi
+
+ if test "x${with_libpng}" = "xbundled"; then
+ USE_EXTERNAL_LIBPNG=false
+ AC_MSG_RESULT([bundled])
+ elif test "x${with_libpng}" = "xsystem"; then
+ PKG_CHECK_MODULES(PNG, libpng,
+ [ LIBPNG_FOUND=yes ],
+ [ LIBPNG_FOUND=no ])
+ if test "x${LIBPNG_FOUND}" = "xyes"; then
+ USE_EXTERNAL_LIBPNG=true
+ AC_MSG_RESULT([system])
+ else
+ AC_MSG_RESULT([system not found])
+ AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!])
+ fi
+ else
+ AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'])
+ fi
+ AC_SUBST(USE_EXTERNAL_LIBPNG)
+
###############################################################################
#
# Check for the zlib library
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index dec8cd5ff8c..76cde66bbce 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -645,6 +645,15 @@ INSTALL_SHAREDSTATEDIR=@sharedstatedir@
# Read-only single-machine data
INSTALL_SYSCONFDIR=@sysconfdir@
+####################################################
+#
+# Libraries
+#
+
+USE_EXTERNAL_LIBPNG:=@USE_EXTERNAL_LIBPNG@
+PNG_LIBS:=@PNG_LIBS@
+PNG_CFLAGS:=@PNG_CFLAGS@
+
####################################################
#
From 90d8f00199e701081552cc1b7470dedfaece89c0 Mon Sep 17 00:00:00 2001
From: Stefan Johansson
Date: Fri, 21 Feb 2014 09:48:52 +0100
Subject: [PATCH 006/116] 8035057: NewSize ergonomics wrong when setting small
or unaligned size on command line
Making sure that if NewSize is set on the command line it should be used for both min and initial size even if it is re-aligned.
Reviewed-by: jwilhelm, jmasa
---
hotspot/src/share/vm/memory/collectorPolicy.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp
index a2f7166eda7..83ec563f153 100644
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp
@@ -304,10 +304,13 @@ void GenCollectorPolicy::initialize_flags() {
}
// Now take the actual NewSize into account. We will silently increase NewSize
- // if the user specified a smaller value.
+ // if the user specified a smaller or unaligned value.
smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment));
if (smallest_new_size != NewSize) {
- FLAG_SET_ERGO(uintx, NewSize, smallest_new_size);
+ // Do not use FLAG_SET_ERGO to update NewSize here, since this will override
+ // if NewSize was set on the command line or not. This information is needed
+ // later when setting the initial and minimum young generation size.
+ NewSize = smallest_new_size;
}
_initial_gen0_size = NewSize;
From 97a80c5f9d349eac80ec0ecdb67f6862bc25bdd7 Mon Sep 17 00:00:00 2001
From: Henry Jen
Date: Tue, 25 Feb 2014 23:38:52 -0800
Subject: [PATCH 007/116] 8019470: Changes needed to compile JDK 8 on MacOS
with clang compiler
Reviewed-by: erikj, ihse
---
common/autoconf/flags.m4 | 39 ++++++++++++++++
common/autoconf/generated-configure.sh | 65 ++++++++++++++++++++++++--
common/autoconf/toolchain.m4 | 23 ++++++++-
3 files changed, 122 insertions(+), 5 deletions(-)
diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4
index 613afc319a1..bcfa1777bcf 100644
--- a/common/autoconf/flags.m4
+++ b/common/autoconf/flags.m4
@@ -133,6 +133,26 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_LIBS],
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # Linking is different on MacOSX
+ SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
+ SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/[$]1'
+ SET_SHARED_LIBRARY_MAPFILE=''
+ else
+ # Default works for linux, might work on other platforms as well.
+ SHARED_LIBRARY_FLAGS='-shared'
+ SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN[$]1'
+ SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Xlinker -soname=[$]1'
+ SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=[$]1'
+ fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ PICFLAG=''
+ C_FLAG_REORDER=''
+ CXX_FLAG_REORDER=''
+
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
@@ -242,6 +262,8 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION],
# Generate make dependency files
if test "x$TOOLCHAIN_TYPE" = xgcc; then
C_FLAG_DEPS="-MMD -MF"
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ C_FLAG_DEPS="-MMD -MF"
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
C_FLAG_DEPS="-xMMD -xMF"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
@@ -260,6 +282,9 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION],
CFLAGS_DEBUG_SYMBOLS="-g"
CXXFLAGS_DEBUG_SYMBOLS="-g"
fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ CFLAGS_DEBUG_SYMBOLS="-g"
+ CXXFLAGS_DEBUG_SYMBOLS="-g"
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
CFLAGS_DEBUG_SYMBOLS="-g -xs"
CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs"
@@ -315,6 +340,20 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION],
C_O_FLAG_NORM="-O2"
C_O_FLAG_NONE="-O0"
fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # On MacOSX we optimize for size, something
+ # we should do for all platforms?
+ C_O_FLAG_HIGHEST="-Os"
+ C_O_FLAG_HI="-Os"
+ C_O_FLAG_NORM="-Os"
+ C_O_FLAG_NONE=""
+ else
+ C_O_FLAG_HIGHEST="-O3"
+ C_O_FLAG_HI="-O3"
+ C_O_FLAG_NORM="-O2"
+ C_O_FLAG_NONE="-O0"
+ fi
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
C_O_FLAG_HIGHEST="-O3"
C_O_FLAG_HI="-O3 -qstrict"
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 7473edb634f..a10b2ef98db 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -4221,7 +4221,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1394011255
+DATE_WHEN_GENERATED=1394150589
###############################################################################
#
@@ -26297,8 +26297,28 @@ fi
# Use indirect variable referencing
toolchain_var_name=VALID_TOOLCHAINS_$OPENJDK_BUILD_OS
VALID_TOOLCHAINS=${!toolchain_var_name}
- # First toolchain type in the list is the default
- DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
+
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # On Mac OS X, default toolchain to clang after Xcode 5
+ XCODE_VERSION_OUTPUT=`xcodebuild -version 2>&1 | $HEAD -n 1`
+ $ECHO "$XCODE_VERSION_OUTPUT" | $GREP "Xcode " > /dev/null
+ if test $? -ne 0; then
+ as_fn_error $? "Failed to determine Xcode version." "$LINENO" 5
+ fi
+ XCODE_MAJOR_VERSION=`$ECHO $XCODE_VERSION_OUTPUT | \
+ $SED -e 's/^Xcode \([1-9][0-9.]*\)/\1/' | \
+ $CUT -f 1 -d .`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Xcode major version: $XCODE_MAJOR_VERSION" >&5
+$as_echo "$as_me: Xcode major version: $XCODE_MAJOR_VERSION" >&6;}
+ if test $XCODE_MAJOR_VERSION -ge 5; then
+ DEFAULT_TOOLCHAIN="clang"
+ else
+ DEFAULT_TOOLCHAIN="gcc"
+ fi
+ else
+ # First toolchain type in the list is the default
+ DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
+ fi
if test "x$with_toolchain_type" = xlist; then
# List all toolchains
@@ -41221,6 +41241,26 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
C_FLAG_REORDER=''
CXX_FLAG_REORDER=''
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # Linking is different on MacOSX
+ SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
+ SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker @loader_path/.'
+ SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/$1'
+ SET_SHARED_LIBRARY_MAPFILE=''
+ else
+ # Default works for linux, might work on other platforms as well.
+ SHARED_LIBRARY_FLAGS='-shared'
+ SET_EXECUTABLE_ORIGIN='-Xlinker -rpath -Xlinker \$$$$ORIGIN$1'
+ SET_SHARED_LIBRARY_ORIGIN="-Xlinker -z -Xlinker origin $SET_EXECUTABLE_ORIGIN"
+ SET_SHARED_LIBRARY_NAME='-Xlinker -soname=$1'
+ SET_SHARED_LIBRARY_MAPFILE='-Xlinker -version-script=$1'
+ fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ PICFLAG=''
+ C_FLAG_REORDER=''
+ CXX_FLAG_REORDER=''
+
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# Linking is different on MacOSX
SHARED_LIBRARY_FLAGS="-dynamiclib -compatibility_version 1.0.0 -current_version 1.0.0 $PICFLAG"
@@ -41297,6 +41337,8 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
# Generate make dependency files
if test "x$TOOLCHAIN_TYPE" = xgcc; then
C_FLAG_DEPS="-MMD -MF"
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ C_FLAG_DEPS="-MMD -MF"
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
C_FLAG_DEPS="-xMMD -xMF"
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
@@ -41315,6 +41357,9 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
CFLAGS_DEBUG_SYMBOLS="-g"
CXXFLAGS_DEBUG_SYMBOLS="-g"
fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ CFLAGS_DEBUG_SYMBOLS="-g"
+ CXXFLAGS_DEBUG_SYMBOLS="-g"
elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then
CFLAGS_DEBUG_SYMBOLS="-g -xs"
CXXFLAGS_DEBUG_SYMBOLS="-g0 -xs"
@@ -41370,6 +41415,20 @@ $as_echo "$ac_cv_c_bigendian" >&6; }
C_O_FLAG_NORM="-O2"
C_O_FLAG_NONE="-O0"
fi
+ elif test "x$TOOLCHAIN_TYPE" = xclang; then
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # On MacOSX we optimize for size, something
+ # we should do for all platforms?
+ C_O_FLAG_HIGHEST="-Os"
+ C_O_FLAG_HI="-Os"
+ C_O_FLAG_NORM="-Os"
+ C_O_FLAG_NONE=""
+ else
+ C_O_FLAG_HIGHEST="-O3"
+ C_O_FLAG_HI="-O3"
+ C_O_FLAG_NORM="-O2"
+ C_O_FLAG_NONE="-O0"
+ fi
elif test "x$TOOLCHAIN_TYPE" = xxlc; then
C_O_FLAG_HIGHEST="-O3"
C_O_FLAG_HI="-O3 -qstrict"
diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4
index 7110d783205..ba57a850219 100644
--- a/common/autoconf/toolchain.m4
+++ b/common/autoconf/toolchain.m4
@@ -96,8 +96,27 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETERMINE_TOOLCHAIN_TYPE],
# Use indirect variable referencing
toolchain_var_name=VALID_TOOLCHAINS_$OPENJDK_BUILD_OS
VALID_TOOLCHAINS=${!toolchain_var_name}
- # First toolchain type in the list is the default
- DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
+
+ if test "x$OPENJDK_TARGET_OS" = xmacosx; then
+ # On Mac OS X, default toolchain to clang after Xcode 5
+ XCODE_VERSION_OUTPUT=`xcodebuild -version 2>&1 | $HEAD -n 1`
+ $ECHO "$XCODE_VERSION_OUTPUT" | $GREP "Xcode " > /dev/null
+ if test $? -ne 0; then
+ AC_MSG_ERROR([Failed to determine Xcode version.])
+ fi
+ XCODE_MAJOR_VERSION=`$ECHO $XCODE_VERSION_OUTPUT | \
+ $SED -e 's/^Xcode \(@<:@1-9@:>@@<:@0-9.@:>@*\)/\1/' | \
+ $CUT -f 1 -d .`
+ AC_MSG_NOTICE([Xcode major version: $XCODE_MAJOR_VERSION])
+ if test $XCODE_MAJOR_VERSION -ge 5; then
+ DEFAULT_TOOLCHAIN="clang"
+ else
+ DEFAULT_TOOLCHAIN="gcc"
+ fi
+ else
+ # First toolchain type in the list is the default
+ DEFAULT_TOOLCHAIN=${VALID_TOOLCHAINS%% *}
+ fi
if test "x$with_toolchain_type" = xlist; then
# List all toolchains
From e1e850a132654a3d95b5d33f07a895662a3346d1 Mon Sep 17 00:00:00 2001
From: Staffan Larsen
Date: Wed, 26 Feb 2014 15:47:44 +0100
Subject: [PATCH 008/116] 8035150: ShouldNotReachHere() in
ConstantPool::copy_entry_to
Reviewed-by: dcubed, mgronlun
---
hotspot/src/share/vm/oops/constantPool.cpp | 1 +
.../TestRedefineWithUnresolvedClass.java | 82 ++++++
.../jvmti/UnresolvedClassAgent.java | 69 +++++
.../jvmti/UnresolvedClassAgent.mf | 3 +
.../oracle/java/testlibrary/ProcessTools.java | 81 +++++-
.../com/oracle/java/testlibrary/Utils.java | 263 ++++++++++++++++++
6 files changed, 497 insertions(+), 2 deletions(-)
create mode 100644 hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
create mode 100644 hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java
create mode 100644 hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf
create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java
diff --git a/hotspot/src/share/vm/oops/constantPool.cpp b/hotspot/src/share/vm/oops/constantPool.cpp
index e008ccb8d4a..9ed7628985d 100644
--- a/hotspot/src/share/vm/oops/constantPool.cpp
+++ b/hotspot/src/share/vm/oops/constantPool.cpp
@@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
} break;
case JVM_CONSTANT_UnresolvedClass:
+ case JVM_CONSTANT_UnresolvedClassInError:
{
// Can be resolved after checking tag, so check the slot first.
CPSlot entry = from_cp->slot_at(from_i);
diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
new file mode 100644
index 00000000000..4f929c49af6
--- /dev/null
+++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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
+ * @summary Redefine a class with an UnresolvedClass reference in the constant pool.
+ * @bug 8035150
+ * @library /testlibrary
+ * @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer
+ * @run main TestRedefineWithUnresolvedClass
+ */
+
+import java.io.File;
+import java.util.Arrays;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+public class TestRedefineWithUnresolvedClass {
+
+ final static String slash = File.separator;
+ final static String testClasses = System.getProperty("test.classes") + slash;
+
+ public static void main(String... args) throws Throwable {
+ // delete this class to cause a NoClassDefFoundError
+ File unresolved = new File(testClasses, "MyUnresolvedClass.class");
+ if (unresolved.exists() && !unresolved.delete()) {
+ throw new Exception("Could not delete: " + unresolved);
+ }
+
+ // build the javaagent
+ buildJar("UnresolvedClassAgent");
+
+ // launch a VM with the javaagent
+ launchTest();
+ }
+
+ private static void buildJar(String jarName) throws Throwable {
+ String testSrc = System.getProperty("test.src", "?") + slash;
+
+ String jarPath = String.format("%s%s.jar", testClasses, jarName);
+ String manifestPath = String.format("%s%s.mf", testSrc, jarName);
+ String className = String.format("%s.class", jarName);
+
+ String[] args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className};
+
+ System.out.println("Running jar " + Arrays.toString(args));
+ sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+ if (!jarTool.run(args)) {
+ throw new Exception("jar failed: args=" + Arrays.toString(args));
+ }
+ }
+
+ private static void launchTest() throws Throwable {
+ String[] args = {
+ "-javaagent:" + testClasses + "UnresolvedClassAgent.jar",
+ "-Dtest.classes=" + testClasses,
+ "UnresolvedClassAgent" };
+ OutputAnalyzer output = ProcessTools.executeTestJvm(args);
+ output.shouldHaveExitValue(0);
+ }
+}
diff --git a/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java
new file mode 100644
index 00000000000..efe7b25a1aa
--- /dev/null
+++ b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+
+/*
+ * This class is present during compilation, but will be deleted before execution.
+ */
+class MyUnresolvedClass {
+ static void bar() {
+ }
+}
+
+class MyRedefinedClass {
+ static void foo() {
+ MyUnresolvedClass.bar();
+ }
+}
+
+public class UnresolvedClassAgent {
+ public static void main(String... args) {
+ }
+
+ public static void premain(String args, Instrumentation inst) throws Exception {
+ try {
+ MyRedefinedClass.foo();
+ } catch(NoClassDefFoundError err) {
+ System.out.println("NoClassDefFoundError (expected)");
+ }
+
+ File f = new File(System.getProperty("test.classes"), "MyRedefinedClass.class");
+ byte[] buf = new byte[(int)f.length()];
+ try (DataInputStream dis = new DataInputStream(new FileInputStream(f))) {
+ dis.readFully(buf);
+ }
+ ClassDefinition cd = new ClassDefinition(MyRedefinedClass.class, buf);
+ inst.redefineClasses(new ClassDefinition[] {cd});
+
+ try {
+ MyRedefinedClass.foo();
+ } catch(NoClassDefFoundError err) {
+ System.out.println("NoClassDefFoundError (expected again)");
+ }
+ }
+}
diff --git a/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf
new file mode 100644
index 00000000000..5570570cd11
--- /dev/null
+++ b/hotspot/test/serviceability/jvmti/UnresolvedClassAgent.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Premain-Class: UnresolvedClassAgent
+Can-Redefine-Classes: true
diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
index 04293905824..649b7a1b38a 100644
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
@@ -163,10 +163,87 @@ public final class ProcessTools {
// Reporting
StringBuilder cmdLine = new StringBuilder();
- for (String cmd : args)
- cmdLine.append(cmd).append(' ');
+ for (String cmd : args) {
+ cmdLine.append(cmd).append(' ');
+ }
System.out.println("Command line: [" + cmdLine.toString() + "]");
return new ProcessBuilder(args.toArray(new String[args.size()]));
}
+
+ /**
+ * Executes a test jvm process, waits for it to finish and returns the process output.
+ * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
+ * The java from the test.jdk is used to execute the command.
+ *
+ * The command line will be like:
+ * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
+ *
+ * @param cmds User specifed arguments.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable {
+ ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
+ return executeProcess(pb);
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ * @param pb The ProcessBuilder to execute.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable {
+ OutputAnalyzer output = null;
+ try {
+ output = new OutputAnalyzer(pb.start());
+ return output;
+ } catch (Throwable t) {
+ System.out.println("executeProcess() failed: " + t);
+ throw t;
+ } finally {
+ System.out.println(getProcessLog(pb, output));
+ }
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ * @param cmds The command line to execute.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeProcess(String... cmds) throws Throwable {
+ return executeProcess(new ProcessBuilder(cmds));
+ }
+
+ /**
+ * Used to log command line, stdout, stderr and exit code from an executed process.
+ * @param pb The executed process.
+ * @param output The output from the process.
+ */
+ public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) {
+ String stderr = output == null ? "null" : output.getStderr();
+ String stdout = output == null ? "null" : output.getStdout();
+ String exitValue = output == null ? "null": Integer.toString(output.getExitValue());
+ StringBuilder logMsg = new StringBuilder();
+ final String nl = System.getProperty("line.separator");
+ logMsg.append("--- ProcessLog ---" + nl);
+ logMsg.append("cmd: " + getCommandLine(pb) + nl);
+ logMsg.append("exitvalue: " + exitValue + nl);
+ logMsg.append("stderr: " + stderr + nl);
+ logMsg.append("stdout: " + stdout + nl);
+ return logMsg.toString();
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ if (pb == null) {
+ return "null";
+ }
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString().trim();
+ }
}
diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java
new file mode 100644
index 00000000000..a0031e706ec
--- /dev/null
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.java.testlibrary;
+
+import static com.oracle.java.testlibrary.Asserts.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Common library for various test helper functions.
+ */
+public final class Utils {
+
+ /**
+ * Returns the sequence used by operating system to separate lines.
+ */
+ public static final String NEW_LINE = System.getProperty("line.separator");
+
+ /**
+ * Returns the value of 'test.vm.opts'system property.
+ */
+ public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
+
+ /**
+ * Returns the value of 'test.java.opts'system property.
+ */
+ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim();
+
+ /**
+ * Returns the value of 'test.timeout.factor' system property
+ * converted to {@code double}.
+ */
+ public static final double TIMEOUT_FACTOR;
+ static {
+ String toFactor = System.getProperty("test.timeout.factor", "1.0");
+ TIMEOUT_FACTOR = Double.parseDouble(toFactor);
+ }
+
+ private Utils() {
+ // Private constructor to prevent class instantiation
+ }
+
+ /**
+ * Returns the list of VM options.
+ *
+ * @return List of VM options
+ */
+ public static List getVmOptions() {
+ return Arrays.asList(safeSplitString(VM_OPTIONS));
+ }
+
+ /**
+ * Returns the list of VM options with -J prefix.
+ *
+ * @return The list of VM options with -J prefix
+ */
+ public static List getForwardVmOptions() {
+ String[] opts = safeSplitString(VM_OPTIONS);
+ for (int i = 0; i < opts.length; i++) {
+ opts[i] = "-J" + opts[i];
+ }
+ return Arrays.asList(opts);
+ }
+
+ /**
+ * Returns the default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+ * @return An array of options, or an empty array if no opptions.
+ */
+ public static String[] getTestJavaOpts() {
+ List opts = new ArrayList();
+ Collections.addAll(opts, safeSplitString(VM_OPTIONS));
+ Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Combines given arguments with default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts
+ * @return The combination of JTReg test java options and user args.
+ */
+ public static String[] addTestJavaOpts(String... userArgs) {
+ List opts = new ArrayList();
+ Collections.addAll(opts, getTestJavaOpts());
+ Collections.addAll(opts, userArgs);
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Splits a string by white space.
+ * Works like String.split(), but returns an empty array
+ * if the string is null or empty.
+ */
+ private static String[] safeSplitString(String s) {
+ if (s == null || s.trim().isEmpty()) {
+ return new String[] {};
+ }
+ return s.trim().split("\\s+");
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString();
+ }
+
+ /**
+ * Returns the free port on the local host.
+ * The function will spin until a valid port number is found.
+ *
+ * @return The port number
+ * @throws InterruptedException if any thread has interrupted the current thread
+ * @throws IOException if an I/O error occurs when opening the socket
+ */
+ public static int getFreePort() throws InterruptedException, IOException {
+ int port = -1;
+
+ while (port <= 0) {
+ Thread.sleep(100);
+
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket(0);
+ port = serverSocket.getLocalPort();
+ } finally {
+ serverSocket.close();
+ }
+ }
+
+ return port;
+ }
+
+ /**
+ * Returns the name of the local host.
+ *
+ * @return The host name
+ * @throws UnknownHostException if IP address of a host could not be determined
+ */
+ public static String getHostname() throws UnknownHostException {
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ String hostName = inetAddress.getHostName();
+
+ assertTrue((hostName != null && !hostName.isEmpty()),
+ "Cannot get hostname");
+
+ return hostName;
+ }
+
+ /**
+ * Uses "jcmd -l" to search for a jvm pid. This function will wait
+ * forever (until jtreg timeout) for the pid to be found.
+ * @param key Regular expression to search for
+ * @return The found pid.
+ */
+ public static int waitForJvmPid(String key) throws Throwable {
+ final long iterationSleepMillis = 250;
+ System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
+ System.out.flush();
+ while (true) {
+ int pid = tryFindJvmPid(key);
+ if (pid >= 0) {
+ return pid;
+ }
+ Thread.sleep(iterationSleepMillis);
+ }
+ }
+
+ /**
+ * Searches for a jvm pid in the output from "jcmd -l".
+ *
+ * Example output from jcmd is:
+ * 12498 sun.tools.jcmd.JCmd -l
+ * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
+ *
+ * @param key A regular expression to search for.
+ * @return The found pid, or -1 if Enot found.
+ * @throws Exception If multiple matching jvms are found.
+ */
+ public static int tryFindJvmPid(String key) throws Throwable {
+ OutputAnalyzer output = null;
+ try {
+ JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
+ jcmdLauncher.addToolArg("-l");
+ output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
+ output.shouldHaveExitValue(0);
+
+ // Search for a line starting with numbers (pid), follwed by the key.
+ Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
+ Matcher matcher = pattern.matcher(output.getStdout());
+
+ int pid = -1;
+ if (matcher.find()) {
+ pid = Integer.parseInt(matcher.group(1));
+ System.out.println("findJvmPid.pid: " + pid);
+ if (matcher.find()) {
+ throw new Exception("Found multiple JVM pids for key: " + key);
+ }
+ }
+ return pid;
+ } catch (Throwable t) {
+ System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
+ throw t;
+ }
+ }
+
+ /**
+ * Returns file content as a list of strings
+ *
+ * @param file File to operate on
+ * @return List of strings
+ * @throws IOException
+ */
+ public static List fileAsList(File file) throws IOException {
+ assertTrue(file.exists() && file.isFile(),
+ file.getAbsolutePath() + " does not exist or not a file");
+ List output = new ArrayList<>();
+ try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) {
+ while (reader.ready()) {
+ output.add(reader.readLine().replace(NEW_LINE, ""));
+ }
+ }
+ return output;
+ }
+
+}
From bfb1c4265701bbf4392f8b7ed7df9653d725e514 Mon Sep 17 00:00:00 2001
From: Yumin Qi
Date: Wed, 26 Feb 2014 15:20:41 -0800
Subject: [PATCH 009/116] 6498581: ThreadInterruptTest3 produces wrong output
on Windows
There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Co-authored-by: David Holmes
Reviewed-by: acorn, kvn
---
hotspot/src/os/windows/vm/os_windows.cpp | 5 +++--
hotspot/src/share/vm/opto/library_call.cpp | 8 +++++++-
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
index 4cc42970ad0..69fb8bc0600 100644
--- a/hotspot/src/os/windows/vm/os_windows.cpp
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
@@ -3619,13 +3619,14 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
"possibility of dangling Thread pointer");
OSThread* osthread = thread->osthread();
- bool interrupted = osthread->interrupted();
// There is no synchronization between the setting of the interrupt
// and it being cleared here. It is critical - see 6535709 - that
// we only clear the interrupt state, and reset the interrupt event,
// if we are going to report that we were indeed interrupted - else
// an interrupt can be "lost", leading to spurious wakeups or lost wakeups
- // depending on the timing
+ // depending on the timing. By checking thread interrupt event to see
+ // if the thread gets real interrupt thus prevent spurious wakeup.
+ bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0);
if (interrupted && clear_interrupted) {
osthread->set_interrupted(false);
ResetEvent(osthread->interrupt_event());
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index 465de355b67..f98878a7bad 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -3246,7 +3246,8 @@ bool LibraryCallKit::inline_native_currentThread() {
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
bool LibraryCallKit::inline_native_isInterrupted() {
// Add a fast path to t.isInterrupted(clear_int):
- // (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int))
+ // (t == Thread.current() &&
+ // (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int)))
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
// So, in the common case that the interrupt bit is false,
// we avoid making a call into the VM. Even if the interrupt bit
@@ -3303,6 +3304,7 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
+#ifndef TARGET_OS_FAMILY_windows
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
Node* clr_arg = argument(1);
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
@@ -3316,6 +3318,10 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
+#else
+ // To return true on Windows you must read the _interrupted field
+ // and check the the event state i.e. take the slow path.
+#endif // TARGET_OS_FAMILY_windows
// (d) Otherwise, go to the slow path.
slow_region->add_req(control());
From 1d81fd35d6b12305a558c101c01a1d46616400ef Mon Sep 17 00:00:00 2001
From: Staffan Larsen
Date: Fri, 28 Feb 2014 14:30:25 +0400
Subject: [PATCH 010/116] 8036010: hs: Some jtreg tests use hard coded ports
Bind to an ephemeral port
Reviewed-by: jbachorik, sla
---
hotspot/test/runtime/6294277/SourceDebugExtension.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hotspot/test/runtime/6294277/SourceDebugExtension.java b/hotspot/test/runtime/6294277/SourceDebugExtension.java
index e8cc8a8bb50..bb650e673ca 100644
--- a/hotspot/test/runtime/6294277/SourceDebugExtension.java
+++ b/hotspot/test/runtime/6294277/SourceDebugExtension.java
@@ -25,7 +25,7 @@
* @test
* @bug 6294277
* @summary java -Xdebug crashes on SourceDebugExtension attribute larger than 64K
- * @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n SourceDebugExtension
+ * @run main/othervm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n SourceDebugExtension
*/
import java.io.*;
From 9bb0f46d009d40362387981fec1d4832805d2dea Mon Sep 17 00:00:00 2001
From: Ivan Gerasimov
Date: Fri, 28 Feb 2014 16:00:40 +0400
Subject: [PATCH 011/116] 8035893: JVM_GetVersionInfo fails to zero structure
Reviewed-by: sla, zgu
---
hotspot/src/share/vm/prims/jvm.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp
index 5003db9119a..1c95046c77b 100644
--- a/hotspot/src/share/vm/prims/jvm.cpp
+++ b/hotspot/src/share/vm/prims/jvm.cpp
@@ -4360,7 +4360,7 @@ JVM_END
JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size))
{
- memset(info, 0, sizeof(info_size));
+ memset(info, 0, info_size);
info->jvm_version = Abstract_VM_Version::jvm_version();
info->update_version = 0; /* 0 in HotSpot Express VM */
From 791b5d2b0ddee61da87909aa7d252542d1d3a911 Mon Sep 17 00:00:00 2001
From: Serguei Spitsyn
Date: Sat, 1 Mar 2014 08:05:55 -0800
Subject: [PATCH 012/116] 6471769: Error: assert(_cur_stack_depth ==
count_frames(),"cur_stack_depth out of sync")
It is more safe to get/update data for suspended threads at a safepoint
Reviewed-by: dcubed, twisti, dholmes
---
hotspot/src/share/vm/prims/jvmtiEnv.cpp | 30 ++++++++--
hotspot/src/share/vm/prims/jvmtiEnvBase.hpp | 55 +++++++++++++++++++
.../share/vm/prims/jvmtiEnvThreadState.cpp | 36 ++++--------
.../share/vm/prims/jvmtiEventController.cpp | 8 +--
.../src/share/vm/prims/jvmtiThreadState.cpp | 31 ++++-------
.../src/share/vm/runtime/vm_operations.hpp | 4 +-
6 files changed, 108 insertions(+), 56 deletions(-)
diff --git a/hotspot/src/share/vm/prims/jvmtiEnv.cpp b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
index 5aba54b6ca9..6dcf2e1bf95 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp
@@ -1464,7 +1464,19 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
// It's fine to update the thread state here because no JVMTI events
// shall be posted for this PopFrame.
- state->update_for_pop_top_frame();
+ // It is only safe to perform the direct operation on the current
+ // thread. All other usage needs to use a vm-safepoint-op for safety.
+ if (java_thread == JavaThread::current()) {
+ state->update_for_pop_top_frame();
+ } else {
+ VM_UpdateForPopTopFrame op(state);
+ VMThread::execute(&op);
+ jvmtiError err = op.result();
+ if (err != JVMTI_ERROR_NONE) {
+ return err;
+ }
+ }
+
java_thread->set_popframe_condition(JavaThread::popframe_pending_bit);
// Set pending step flag for this popframe and it is cleared when next
// step event is posted.
@@ -1505,6 +1517,7 @@ JvmtiEnv::GetFrameLocation(JavaThread* java_thread, jint depth, jmethodID* metho
// depth - pre-checked as non-negative
jvmtiError
JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
+ jvmtiError err = JVMTI_ERROR_NONE;
ResourceMark rm;
uint32_t debug_bits = 0;
@@ -1532,10 +1545,17 @@ JvmtiEnv::NotifyFramePop(JavaThread* java_thread, jint depth) {
assert(vf->frame_pointer() != NULL, "frame pointer mustn't be NULL");
- int frame_number = state->count_frames() - depth;
- state->env_thread_state(this)->set_frame_pop(frame_number);
-
- return JVMTI_ERROR_NONE;
+ // It is only safe to perform the direct operation on the current
+ // thread. All other usage needs to use a vm-safepoint-op for safety.
+ if (java_thread == JavaThread::current()) {
+ int frame_number = state->count_frames() - depth;
+ state->env_thread_state(this)->set_frame_pop(frame_number);
+ } else {
+ VM_SetFramePop op(this, state, depth);
+ VMThread::execute(&op);
+ err = op.result();
+ }
+ return err;
} /* end NotifyFramePop */
diff --git a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
index 0f9495945ec..f3c06c30c34 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.hpp
@@ -29,6 +29,7 @@
#include "prims/jvmtiEnvThreadState.hpp"
#include "prims/jvmtiEventController.hpp"
#include "prims/jvmtiThreadState.hpp"
+#include "prims/jvmtiThreadState.inline.hpp"
#include "runtime/fieldDescriptor.hpp"
#include "runtime/frame.hpp"
#include "runtime/handles.inline.hpp"
@@ -334,6 +335,60 @@ class JvmtiEnvIterator : public StackObj {
JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); }
};
+// VM operation to update for pop top frame.
+class VM_UpdateForPopTopFrame : public VM_Operation {
+private:
+ JvmtiThreadState* _state;
+ jvmtiError _result;
+
+public:
+ VM_UpdateForPopTopFrame(JvmtiThreadState* state) {
+ _state = state;
+ _result = JVMTI_ERROR_NONE;
+ }
+ VMOp_Type type() const { return VMOp_UpdateForPopTopFrame; }
+ jvmtiError result() { return _result; }
+ void doit() {
+ JavaThread* jt = _state->get_thread();
+ if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
+ _state->update_for_pop_top_frame();
+ } else {
+ _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
+ }
+ }
+};
+
+// VM operation to set frame pop.
+class VM_SetFramePop : public VM_Operation {
+private:
+ JvmtiEnv *_env;
+ JvmtiThreadState* _state;
+ jint _depth;
+ jvmtiError _result;
+
+public:
+ VM_SetFramePop(JvmtiEnv *env, JvmtiThreadState* state, jint depth) {
+ _env = env;
+ _state = state;
+ _depth = depth;
+ _result = JVMTI_ERROR_NONE;
+ }
+ // Nested operation must be allowed for the VM_EnterInterpOnlyMode that is
+ // called from the JvmtiEventControllerPrivate::recompute_thread_enabled.
+ bool allow_nested_vm_operations() const { return true; }
+ VMOp_Type type() const { return VMOp_SetFramePop; }
+ jvmtiError result() { return _result; }
+ void doit() {
+ JavaThread* jt = _state->get_thread();
+ if (Threads::includes(jt) && !jt->is_exiting() && jt->threadObj() != NULL) {
+ int frame_number = _state->count_frames() - _depth;
+ _state->env_thread_state((JvmtiEnvBase*)_env)->set_frame_pop(frame_number);
+ } else {
+ _result = JVMTI_ERROR_THREAD_NOT_ALIVE;
+ }
+ }
+};
+
// VM operation to get monitor information with stack depth.
class VM_GetOwnedMonitorInfo : public VM_Operation {
diff --git a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp
index ab3c5f445b3..3b290af1a0d 100644
--- a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.cpp
@@ -190,12 +190,8 @@ void JvmtiEnvThreadState::compare_and_set_current_location(Method* new_method,
JvmtiFramePops* JvmtiEnvThreadState::get_frame_pops() {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "frame pop data only accessible from same thread or while suspended");
-
+ assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "frame pop data only accessible from same thread or at safepoint");
if (_frame_pops == NULL) {
_frame_pops = new JvmtiFramePops();
assert(_frame_pops != NULL, "_frame_pops != NULL");
@@ -209,44 +205,32 @@ bool JvmtiEnvThreadState::has_frame_pops() {
}
void JvmtiEnvThreadState::set_frame_pop(int frame_number) {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "frame pop data only accessible from same thread or while suspended");
+ assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::set_frame_pop(this, fpop);
}
void JvmtiEnvThreadState::clear_frame_pop(int frame_number) {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "frame pop data only accessible from same thread or while suspended");
+ assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::clear_frame_pop(this, fpop);
}
void JvmtiEnvThreadState::clear_to_frame_pop(int frame_number) {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "frame pop data only accessible from same thread or while suspended");
+ assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "frame pop data only accessible from same thread or at safepoint");
JvmtiFramePop fpop(frame_number);
JvmtiEventController::clear_to_frame_pop(this, fpop);
}
bool JvmtiEnvThreadState::is_frame_pop(int cur_frame_number) {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(get_thread() == Thread::current() || JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "frame pop data only accessible from same thread or while suspended");
+ assert(get_thread() == Thread::current() || SafepointSynchronize::is_at_safepoint(),
+ "frame pop data only accessible from same thread or at safepoint");
if (!get_thread()->is_interp_only_mode() || _frame_pops == NULL) {
return false;
}
diff --git a/hotspot/src/share/vm/prims/jvmtiEventController.cpp b/hotspot/src/share/vm/prims/jvmtiEventController.cpp
index 52bfb1f7632..dff9989736e 100644
--- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiEventController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -989,21 +989,21 @@ JvmtiEventController::set_extension_event_callback(JvmtiEnvBase *env,
void
JvmtiEventController::set_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
- MutexLocker mu(JvmtiThreadState_lock);
+ MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::set_frame_pop(ets, fpop);
}
void
JvmtiEventController::clear_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
- MutexLocker mu(JvmtiThreadState_lock);
+ MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::clear_frame_pop(ets, fpop);
}
void
JvmtiEventController::clear_to_frame_pop(JvmtiEnvThreadState *ets, JvmtiFramePop fpop) {
- MutexLocker mu(JvmtiThreadState_lock);
+ MutexLockerEx mu(SafepointSynchronize::is_at_safepoint() ? NULL : JvmtiThreadState_lock);
JvmtiEventControllerPrivate::clear_to_frame_pop(ets, fpop);
}
diff --git a/hotspot/src/share/vm/prims/jvmtiThreadState.cpp b/hotspot/src/share/vm/prims/jvmtiThreadState.cpp
index 34b5bdc8f44..42f4854bd89 100644
--- a/hotspot/src/share/vm/prims/jvmtiThreadState.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiThreadState.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -63,6 +63,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread)
_vm_object_alloc_event_collector = NULL;
_the_class_for_redefinition_verification = NULL;
_scratch_class_for_redefinition_verification = NULL;
+ _cur_stack_depth = UNKNOWN_STACK_DEPTH;
// JVMTI ForceEarlyReturn support
_pending_step_for_earlyret = false;
@@ -213,12 +214,9 @@ void JvmtiThreadState::leave_interp_only_mode() {
// Helper routine used in several places
int JvmtiThreadState::count_frames() {
-#ifdef ASSERT
- uint32_t debug_bits = 0;
-#endif
- assert(SafepointSynchronize::is_at_safepoint() ||
- JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "at safepoint or must be suspended");
+ guarantee(SafepointSynchronize::is_at_safepoint() ||
+ (JavaThread *)Thread::current() == get_thread(),
+ "must be current thread or at safepoint");
if (!get_thread()->has_last_Java_frame()) return 0; // no Java frames
@@ -243,15 +241,9 @@ int JvmtiThreadState::count_frames() {
void JvmtiThreadState::invalidate_cur_stack_depth() {
- Thread *cur = Thread::current();
- uint32_t debug_bits = 0;
-
- // The caller can be the VMThread at a safepoint, the current thread
- // or the target thread must be suspended.
- guarantee((cur->is_VM_thread() && SafepointSynchronize::is_at_safepoint()) ||
- (JavaThread *)cur == get_thread() ||
- JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "sanity check");
+ guarantee(SafepointSynchronize::is_at_safepoint() ||
+ (JavaThread *)Thread::current() == get_thread(),
+ "must be current thread or at safepoint");
_cur_stack_depth = UNKNOWN_STACK_DEPTH;
}
@@ -280,10 +272,9 @@ void JvmtiThreadState::decr_cur_stack_depth() {
}
int JvmtiThreadState::cur_stack_depth() {
- uint32_t debug_bits = 0;
- guarantee(JavaThread::current() == get_thread() ||
- JvmtiEnv::is_thread_fully_suspended(get_thread(), false, &debug_bits),
- "must be current thread or suspended");
+ guarantee(SafepointSynchronize::is_at_safepoint() ||
+ (JavaThread *)Thread::current() == get_thread(),
+ "must be current thread or at safepoint");
if (!is_interp_only_mode() || _cur_stack_depth == UNKNOWN_STACK_DEPTH) {
_cur_stack_depth = count_frames();
diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp
index 005fc11780b..a3a58e4d4c3 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -74,6 +74,8 @@
template(PopulateDumpSharedSpace) \
template(JNIFunctionTableCopier) \
template(RedefineClasses) \
+ template(UpdateForPopTopFrame) \
+ template(SetFramePop) \
template(GetOwnedMonitorInfo) \
template(GetObjectMonitorUsage) \
template(GetCurrentContendedMonitor) \
From 4482a30c613d457ddb1dcc66a56521bfba7d03e0 Mon Sep 17 00:00:00 2001
From: Dmitry Samersoff
Date: Sat, 1 Mar 2014 09:56:15 -0800
Subject: [PATCH 013/116] 8036102: part of the fix for 6498581 lost in mismerge
Restore code lost in mis-merge
Reviewed-by: dcubed
---
hotspot/src/share/vm/opto/library_call.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index 73c6e9090f9..bd2ef020bb2 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -3180,7 +3180,8 @@ bool LibraryCallKit::inline_native_currentThread() {
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
bool LibraryCallKit::inline_native_isInterrupted() {
// Add a fast path to t.isInterrupted(clear_int):
- // (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int))
+ // (t == Thread.current() &&
+ // (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int)))
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
// So, in the common case that the interrupt bit is false,
// we avoid making a call into the VM. Even if the interrupt bit
@@ -3237,6 +3238,7 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
+#ifndef TARGET_OS_FAMILY_windows
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
Node* clr_arg = argument(1);
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
@@ -3250,6 +3252,10 @@ bool LibraryCallKit::inline_native_isInterrupted() {
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
+#else
+ // To return true on Windows you must read the _interrupted field
+ // and check the the event state i.e. take the slow path.
+#endif // TARGET_OS_FAMILY_windows
// (d) Otherwise, go to the slow path.
slow_region->add_req(control());
From e8d4b7aee3a4f35508353e67c7c05a77ca020924 Mon Sep 17 00:00:00 2001
From: Coleen Phillimore
Date: Tue, 4 Mar 2014 09:57:16 -0500
Subject: [PATCH 014/116] 8036547:
test/runtime/CompressedOops/CompressedClassPointers.java fails with product
build since -XX:+PrintMiscellaneous is a debug only flag
Use PrintCompressedOopsMode and these other flags that match printing compressed oop information
Reviewed-by: ctornqvi, sla
---
hotspot/src/share/vm/runtime/arguments.cpp | 3 ++-
.../test/runtime/CompressedOops/CompressedClassPointers.java | 4 ++--
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index 1e02bf0cad8..c6549f88665 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -1699,7 +1699,8 @@ void Arguments::set_heap_size() {
// HeapBaseMinAddress can be greater than default but not less than.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) {
if (HeapBaseMinAddress < DefaultHeapBaseMinAddress) {
- if (PrintMiscellaneous && Verbose) { // matches compressed oops printing flags
+ // matches compressed oops printing flags
+ if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
jio_fprintf(defaultStream::error_stream(),
"HeapBaseMinAddress must be at least " UINTX_FORMAT
" (" UINTX_FORMAT "G) which is greater than value given "
diff --git a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
index e801d5b87df..bb68a6ff074 100644
--- a/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
+++ b/hotspot/test/runtime/CompressedOops/CompressedClassPointers.java
@@ -83,8 +83,8 @@ public class CompressedClassPointers {
public static void heapBaseMinAddressTest() throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:HeapBaseMinAddress=1m",
- "-XX:+PrintMiscellaneous",
- "-XX:+Verbose",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+PrintCompressedOopsMode",
"-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("HeapBaseMinAddress must be at least");
From 4b9933a0120150e5d7f51de791d11c08507e23d5 Mon Sep 17 00:00:00 2001
From: Goetz Lindenmaier
Date: Mon, 3 Mar 2014 11:54:35 +0100
Subject: [PATCH 015/116] 8036122: Fix warning 'format not a string literal'
Reviewed-by: mduigou, kvn
---
hotspot/make/bsd/makefiles/gcc.make | 2 +-
hotspot/make/linux/makefiles/gcc.make | 2 +-
hotspot/make/solaris/makefiles/gcc.make | 2 +-
hotspot/src/os/linux/vm/os_linux.cpp | 6 ++---
.../src/share/vm/compiler/compilerOracle.cpp | 27 +++----------------
5 files changed, 10 insertions(+), 29 deletions(-)
diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make
index 9c9cef07f82..2a0eab17ef9 100644
--- a/hotspot/make/bsd/makefiles/gcc.make
+++ b/hotspot/make/bsd/makefiles/gcc.make
@@ -260,7 +260,7 @@ ifeq ($(USE_CLANG), true)
WARNINGS_ARE_ERRORS += -Wno-empty-body
endif
-WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wformat=2 -Wno-error=format-nonliteral
+WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wformat=2
ifeq ($(USE_CLANG),)
# Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit
diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make
index 071c36e5876..87ef16faed8 100644
--- a/hotspot/make/linux/makefiles/gcc.make
+++ b/hotspot/make/linux/makefiles/gcc.make
@@ -215,7 +215,7 @@ ifeq ($(USE_CLANG), true)
WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body
endif
-WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2 -Wno-error=format-nonliteral
+WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef -Wunused-function -Wunused-value -Wformat=2
ifeq ($(USE_CLANG),)
# Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit
diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make
index 627691c78f3..94778592ece 100644
--- a/hotspot/make/solaris/makefiles/gcc.make
+++ b/hotspot/make/solaris/makefiles/gcc.make
@@ -118,7 +118,7 @@ endif
# Compiler warnings are treated as errors
WARNINGS_ARE_ERRORS = -Werror
# Enable these warnings. See 'info gcc' about details on these options
-WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef -Wformat=2 -Wno-error=format-nonliteral
+WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef -Wformat=2
CFLAGS_WARN/DEFAULT = $(WARNINGS_ARE_ERRORS) $(WARNING_FLAGS)
# Special cases
CFLAGS_WARN/BYFILE = $(CFLAGS_WARN/$@)$(CFLAGS_WARN/DEFAULT$(CFLAGS_WARN/$@))
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index 4490c5f2f71..20ef1e10fb4 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -5284,7 +5284,6 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
static bool proc_task_unchecked = true;
- static const char *proc_stat_path = "/proc/%d/stat";
pid_t tid = thread->osthread()->thread_id();
char *s;
char stat[2048];
@@ -5297,6 +5296,8 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
long ldummy;
FILE *fp;
+ snprintf(proc_name, 64, "/proc/%d/stat", tid);
+
// The /proc//stat aggregates per-process usage on
// new Linux kernels 2.6+ where NPTL is supported.
// The /proc/self/task//stat still has the per-thread usage.
@@ -5308,12 +5309,11 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
proc_task_unchecked = false;
fp = fopen("/proc/self/task", "r");
if (fp != NULL) {
- proc_stat_path = "/proc/self/task/%d/stat";
+ snprintf(proc_name, 64, "/proc/self/task/%d/stat", tid);
fclose(fp);
}
}
- sprintf(proc_name, proc_stat_path, tid);
fp = fopen(proc_name, "r");
if ( fp == NULL ) return -1;
statlen = fread(stat, 1, 2047, fp);
diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp
index cb5068dc4c6..582ec675d4d 100644
--- a/hotspot/src/share/vm/compiler/compilerOracle.cpp
+++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp
@@ -374,25 +374,8 @@ static void usage() {
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
#define RANGE0 "[*" RANGEBASE "]"
-#define RANGEDOT "[*" RANGEBASE ".]"
#define RANGESLASH "[*" RANGEBASE "/]"
-
-// Accept several syntaxes for these patterns
-// original syntax
-// cmd java.lang.String foo
-// PrintCompilation syntax
-// cmd java.lang.String::foo
-// VM syntax
-// cmd java/lang/String[. ]foo
-//
-
-static const char* patterns[] = {
- "%*[ \t]%255" RANGEDOT " " "%255" RANGE0 "%n",
- "%*[ \t]%255" RANGEDOT "::" "%255" RANGE0 "%n",
- "%*[ \t]%255" RANGESLASH "%*[ .]" "%255" RANGE0 "%n",
-};
-
static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) {
int match = MethodMatcher::Exact;
while (name[0] == '*') {
@@ -421,12 +404,10 @@ static bool scan_line(const char * line,
int* bytes_read, const char*& error_msg) {
*bytes_read = 0;
error_msg = NULL;
- for (uint i = 0; i < ARRAY_SIZE(patterns); i++) {
- if (2 == sscanf(line, patterns[i], class_name, method_name, bytes_read)) {
- *c_mode = check_mode(class_name, error_msg);
- *m_mode = check_mode(method_name, error_msg);
- return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown;
- }
+ if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) {
+ *c_mode = check_mode(class_name, error_msg);
+ *m_mode = check_mode(method_name, error_msg);
+ return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown;
}
return false;
}
From c4bd0f58d316bafe4cb670d09ee932e79c1ae929 Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Mon, 3 Mar 2014 15:54:45 +0400
Subject: [PATCH 016/116] 8033380: Experimental VM flag to enforce access
atomicity
-XX:+AlwaysAtomicAccesses to unconditionally enforce the access atomicity.
Reviewed-by: roland, kvn, iveresov
---
hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 6 ++--
hotspot/src/share/vm/c1/c1_Runtime1.cpp | 34 ++++++++++++++++-----
hotspot/src/share/vm/opto/parse3.cpp | 6 ++--
hotspot/src/share/vm/runtime/globals.hpp | 3 ++
4 files changed, 37 insertions(+), 12 deletions(-)
diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
index 5ed04765618..ca8383b2542 100644
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -1734,7 +1734,8 @@ void LIRGenerator::do_StoreField(StoreField* x) {
(info ? new CodeEmitInfo(info) : NULL));
}
- if (is_volatile && !needs_patching) {
+ bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
+ if (needs_atomic_access && !needs_patching) {
volatile_field_store(value.result(), address, info);
} else {
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
@@ -1807,7 +1808,8 @@ void LIRGenerator::do_LoadField(LoadField* x) {
address = generate_address(object.result(), x->offset(), field_type);
}
- if (is_volatile && !needs_patching) {
+ bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
+ if (needs_atomic_access && !needs_patching) {
volatile_field_load(address, reg, info);
} else {
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
index e3bac09c5b4..11542c4a50b 100644
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp
@@ -809,11 +809,10 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
int bci = vfst.bci();
Bytecodes::Code code = caller_method()->java_code_at(bci);
-#ifndef PRODUCT
// this is used by assertions in the access_field_patching_id
BasicType patch_field_type = T_ILLEGAL;
-#endif // PRODUCT
bool deoptimize_for_volatile = false;
+ bool deoptimize_for_atomic = false;
int patch_field_offset = -1;
KlassHandle init_klass(THREAD, NULL); // klass needed by load_klass_patching code
KlassHandle load_klass(THREAD, NULL); // klass needed by load_klass_patching code
@@ -839,11 +838,24 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
// is the path for patching field offsets. load_klass is only
// used for patching references to oops which don't need special
// handling in the volatile case.
+
deoptimize_for_volatile = result.access_flags().is_volatile();
-#ifndef PRODUCT
+ // If we are patching a field which should be atomic, then
+ // the generated code is not correct either, force deoptimizing.
+ // We need to only cover T_LONG and T_DOUBLE fields, as we can
+ // break access atomicity only for them.
+
+ // Strictly speaking, the deoptimizaation on 64-bit platforms
+ // is unnecessary, and T_LONG stores on 32-bit platforms need
+ // to be handled by special patching code when AlwaysAtomicAccesses
+ // becomes product feature. At this point, we are still going
+ // for the deoptimization for consistency against volatile
+ // accesses.
+
patch_field_type = result.field_type();
-#endif
+ deoptimize_for_atomic = (AlwaysAtomicAccesses && (patch_field_type == T_DOUBLE || patch_field_type == T_LONG));
+
} else if (load_klass_or_mirror_patch_id) {
Klass* k = NULL;
switch (code) {
@@ -918,13 +930,19 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
ShouldNotReachHere();
}
- if (deoptimize_for_volatile) {
- // At compile time we assumed the field wasn't volatile but after
- // loading it turns out it was volatile so we have to throw the
+ if (deoptimize_for_volatile || deoptimize_for_atomic) {
+ // At compile time we assumed the field wasn't volatile/atomic but after
+ // loading it turns out it was volatile/atomic so we have to throw the
// compiled code out and let it be regenerated.
if (TracePatching) {
- tty->print_cr("Deoptimizing for patching volatile field reference");
+ if (deoptimize_for_volatile) {
+ tty->print_cr("Deoptimizing for patching volatile field reference");
+ }
+ if (deoptimize_for_atomic) {
+ tty->print_cr("Deoptimizing for patching atomic field reference");
+ }
}
+
// It's possible the nmethod was invalidated in the last
// safepoint, but if it's still alive then make it not_entrant.
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp
index 466e1ca3b90..0e3eddde236 100644
--- a/hotspot/src/share/vm/opto/parse3.cpp
+++ b/hotspot/src/share/vm/opto/parse3.cpp
@@ -233,7 +233,8 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
// Build the load.
//
MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered;
- Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, is_vol);
+ bool needs_atomic_access = is_vol || AlwaysAtomicAccesses;
+ Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, needs_atomic_access);
// Adjust Java stack
if (type2size[bt] == 1)
@@ -314,7 +315,8 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
}
store = store_oop_to_object(control(), obj, adr, adr_type, val, field_type, bt, mo);
} else {
- store = store_to_memory(control(), adr, val, bt, adr_type, mo, is_vol);
+ bool needs_atomic_access = is_vol || AlwaysAtomicAccesses;
+ store = store_to_memory(control(), adr, val, bt, adr_type, mo, needs_atomic_access);
}
// If reference is volatile, prevent following volatiles ops from
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index b971907b980..a9eb5a1176e 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -3864,6 +3864,9 @@ class CommandLineFlags {
"Allocation less than this value will be allocated " \
"using malloc. Larger allocations will use mmap.") \
\
+ experimental(bool, AlwaysAtomicAccesses, false, \
+ "Accesses to all variables should always be atomic") \
+ \
product(bool, EnableTracing, false, \
"Enable event-based tracing") \
\
From 1d10b6813e2749cf1b0c073aac43f5d7b4c4209e Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Mon, 3 Mar 2014 15:31:27 +0400
Subject: [PATCH 017/116] 8031818: Experimental VM flag for enforcing safe
object construction
-XX:+AlwaysSafeConstructors to unconditionally emit the trailing constructor barrier.
Reviewed-by: kvn, roland
---
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 6 +-
hotspot/src/share/vm/c1/c1_IR.cpp | 1 +
hotspot/src/share/vm/c1/c1_IR.hpp | 4 ++
hotspot/src/share/vm/opto/parse.hpp | 6 ++
hotspot/src/share/vm/opto/parse1.cpp | 64 ++++++++++++++-------
hotspot/src/share/vm/opto/parse3.cpp | 12 +++-
hotspot/src/share/vm/runtime/globals.hpp | 3 +
7 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
index 7cb6d3dfa47..389eaf29b47 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -1436,7 +1436,7 @@ void GraphBuilder::method_return(Value x) {
bool need_mem_bar = false;
if (method()->name() == ciSymbol::object_initializer_name() &&
- scope()->wrote_final()) {
+ (scope()->wrote_final() || (AlwaysSafeConstructors && scope()->wrote_fields()))) {
need_mem_bar = true;
}
@@ -1550,6 +1550,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
scope()->set_wrote_final();
}
+ if (code == Bytecodes::_putfield) {
+ scope()->set_wrote_fields();
+ }
+
const int offset = !needs_patching ? field->offset() : -1;
switch (code) {
case Bytecodes::_getstatic: {
diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp
index c377e56ecef..b2a4fbbc494 100644
--- a/hotspot/src/share/vm/c1/c1_IR.cpp
+++ b/hotspot/src/share/vm/c1/c1_IR.cpp
@@ -142,6 +142,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe
_number_of_locks = 0;
_monitor_pairing_ok = method->has_balanced_monitors();
_wrote_final = false;
+ _wrote_fields = false;
_start = NULL;
if (osr_bci == -1) {
diff --git a/hotspot/src/share/vm/c1/c1_IR.hpp b/hotspot/src/share/vm/c1/c1_IR.hpp
index ba1abee0d01..6dc0e3a98bd 100644
--- a/hotspot/src/share/vm/c1/c1_IR.hpp
+++ b/hotspot/src/share/vm/c1/c1_IR.hpp
@@ -150,6 +150,7 @@ class IRScope: public CompilationResourceObj {
int _number_of_locks; // the number of monitor lock slots needed
bool _monitor_pairing_ok; // the monitor pairing info
bool _wrote_final; // has written final field
+ bool _wrote_fields; // has written fields
BlockBegin* _start; // the start block, successsors are method entries
BitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable
@@ -184,6 +185,9 @@ class IRScope: public CompilationResourceObj {
BlockBegin* start() const { return _start; }
void set_wrote_final() { _wrote_final = true; }
bool wrote_final () const { return _wrote_final; }
+ void set_wrote_fields() { _wrote_fields = true; }
+ bool wrote_fields () const { return _wrote_fields; }
+
};
diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp
index cca8a8b6c3c..092e40a7f64 100644
--- a/hotspot/src/share/vm/opto/parse.hpp
+++ b/hotspot/src/share/vm/opto/parse.hpp
@@ -338,6 +338,8 @@ class Parse : public GraphKit {
GraphKit _exits; // Record all normal returns and throws here.
bool _wrote_final; // Did we write a final field?
bool _wrote_volatile; // Did we write a volatile field?
+ bool _wrote_stable; // Did we write a @Stable field?
+ bool _wrote_fields; // Did we write any field?
bool _count_invocations; // update and test invocation counter
bool _method_data_update; // update method data oop
Node* _alloc_with_final; // An allocation node with final field
@@ -383,6 +385,10 @@ class Parse : public GraphKit {
void set_wrote_final(bool z) { _wrote_final = z; }
bool wrote_volatile() const { return _wrote_volatile; }
void set_wrote_volatile(bool z) { _wrote_volatile = z; }
+ bool wrote_stable() const { return _wrote_stable; }
+ void set_wrote_stable(bool z) { _wrote_stable = z; }
+ bool wrote_fields() const { return _wrote_fields; }
+ void set_wrote_fields(bool z) { _wrote_fields = z; }
bool count_invocations() const { return _count_invocations; }
bool method_data_update() const { return _method_data_update; }
Node* alloc_with_final() const { return _alloc_with_final; }
diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp
index 74b1f1a4ac8..db50f98492b 100644
--- a/hotspot/src/share/vm/opto/parse1.cpp
+++ b/hotspot/src/share/vm/opto/parse1.cpp
@@ -391,6 +391,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Pars
_depth = 1 + (caller->has_method() ? caller->depth() : 0);
_wrote_final = false;
_wrote_volatile = false;
+ _wrote_stable = false;
+ _wrote_fields = false;
_alloc_with_final = NULL;
_entry_bci = InvocationEntryBci;
_tf = NULL;
@@ -908,26 +910,35 @@ void Parse::do_exits() {
Node* iophi = _exits.i_o();
_exits.set_i_o(gvn().transform(iophi));
- // On PPC64, also add MemBarRelease for constructors which write
- // volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu
- // is set on PPC64, no sync instruction is issued after volatile
- // stores. We want to quarantee the same behaviour as on platforms
- // with total store order, although this is not required by the Java
- // memory model. So as with finals, we add a barrier here.
- if (wrote_final() PPC64_ONLY(|| (wrote_volatile() && method()->is_initializer()))) {
- // This method (which must be a constructor by the rules of Java)
- // wrote a final. The effects of all initializations must be
- // committed to memory before any code after the constructor
- // publishes the reference to the newly constructor object.
- // Rather than wait for the publication, we simply block the
- // writes here. Rather than put a barrier on only those writes
- // which are required to complete, we force all writes to complete.
- //
- // "All bets are off" unless the first publication occurs after a
- // normal return from the constructor. We do not attempt to detect
- // such unusual early publications. But no barrier is needed on
- // exceptional returns, since they cannot publish normally.
- //
+ // Figure out if we need to emit the trailing barrier. The barrier is only
+ // needed in the constructors, and only in three cases:
+ //
+ // 1. The constructor wrote a final. The effects of all initializations
+ // must be committed to memory before any code after the constructor
+ // publishes the reference to the newly constructed object. Rather
+ // than wait for the publication, we simply block the writes here.
+ // Rather than put a barrier on only those writes which are required
+ // to complete, we force all writes to complete.
+ //
+ // 2. On PPC64, also add MemBarRelease for constructors which write
+ // volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu
+ // is set on PPC64, no sync instruction is issued after volatile
+ // stores. We want to guarantee the same behavior as on platforms
+ // with total store order, although this is not required by the Java
+ // memory model. So as with finals, we add a barrier here.
+ //
+ // 3. Experimental VM option is used to force the barrier if any field
+ // was written out in the constructor.
+ //
+ // "All bets are off" unless the first publication occurs after a
+ // normal return from the constructor. We do not attempt to detect
+ // such unusual early publications. But no barrier is needed on
+ // exceptional returns, since they cannot publish normally.
+ //
+ if (method()->is_initializer() &&
+ (wrote_final() ||
+ PPC64_ONLY(wrote_volatile() ||)
+ (AlwaysSafeConstructors && wrote_fields()))) {
_exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
#ifndef PRODUCT
if (PrintOpto && (Verbose || WizardMode)) {
@@ -937,6 +948,19 @@ void Parse::do_exits() {
#endif
}
+ // Any method can write a @Stable field; insert memory barriers after
+ // those also. If there is a predecessor allocation node, bind the
+ // barrier there.
+ if (wrote_stable()) {
+ _exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
+#ifndef PRODUCT
+ if (PrintOpto && (Verbose || WizardMode)) {
+ method()->print_name();
+ tty->print_cr(" writes @Stable and needs a memory barrier");
+ }
+#endif
+ }
+
for (MergeMemStream mms(_exits.merged_memory()); mms.next_non_empty(); ) {
// transform each slice of the original memphi:
mms.set_memory(_gvn.transform(mms.memory()));
diff --git a/hotspot/src/share/vm/opto/parse3.cpp b/hotspot/src/share/vm/opto/parse3.cpp
index 0e3eddde236..1f7ea1d3f8b 100644
--- a/hotspot/src/share/vm/opto/parse3.cpp
+++ b/hotspot/src/share/vm/opto/parse3.cpp
@@ -334,13 +334,23 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
}
}
+ if (is_field) {
+ set_wrote_fields(true);
+ }
+
// If the field is final, the rules of Java say we are in or .
// Note the presence of writes to final non-static fields, so that we
// can insert a memory barrier later on to keep the writes from floating
// out of the constructor.
// Any method can write a @Stable field; insert memory barriers after those also.
if (is_field && (field->is_final() || field->is_stable())) {
- set_wrote_final(true);
+ if (field->is_final()) {
+ set_wrote_final(true);
+ }
+ if (field->is_stable()) {
+ set_wrote_stable(true);
+ }
+
// Preserve allocation ptr to create precedent edge to it in membar
// generated on exit from constructor.
if (C->eliminate_boxing() &&
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index a9eb5a1176e..866cff8349a 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -535,6 +535,9 @@ class CommandLineFlags {
develop(bool, CleanChunkPoolAsync, falseInEmbedded, \
"Clean the chunk pool asynchronously") \
\
+ experimental(bool, AlwaysSafeConstructors, false, \
+ "Force safe construction, as if all fields are final.") \
+ \
/* Temporary: See 6948537 */ \
experimental(bool, UseMemSetInBOT, true, \
"(Unstable) uses memset in BOT updates in GC code") \
From 1a95f3a409faf70f7ee0281bb7762f0a5ffe844b Mon Sep 17 00:00:00 2001
From: Coleen Phillimore
Date: Mon, 3 Mar 2014 13:58:52 -0500
Subject: [PATCH 018/116] 8035735: Metaspace::contains become extremely slow in
some cases
Call is_metadata instead which does less work for the call in debugInfo.hpp which is called for all compiled code stack frames.
Reviewed-by: jmasa, dcubed
---
hotspot/src/share/vm/code/debugInfo.hpp | 6 +++---
hotspot/src/share/vm/oops/metadata.hpp | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/hotspot/src/share/vm/code/debugInfo.hpp b/hotspot/src/share/vm/code/debugInfo.hpp
index cf0a9a6d39f..287ff876cb0 100644
--- a/hotspot/src/share/vm/code/debugInfo.hpp
+++ b/hotspot/src/share/vm/code/debugInfo.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -273,8 +273,8 @@ class DebugInfoReadStream : public CompressedReadStream {
}
Method* read_method() {
Method* o = (Method*)(code()->metadata_at(read_int()));
- assert(o == NULL ||
- o->is_metaspace_object(), "meta data only");
+ // is_metadata() is a faster check than is_metaspace_object()
+ assert(o == NULL || o->is_metadata(), "meta data only");
return o;
}
ScopeValue* read_object_value();
diff --git a/hotspot/src/share/vm/oops/metadata.hpp b/hotspot/src/share/vm/oops/metadata.hpp
index 84a60893e81..dc52c452ee3 100644
--- a/hotspot/src/share/vm/oops/metadata.hpp
+++ b/hotspot/src/share/vm/oops/metadata.hpp
@@ -42,6 +42,7 @@ class Metadata : public MetaspaceObj {
// Rehashing support for tables containing pointers to this
unsigned int new_hash(juint seed) { ShouldNotReachHere(); return 0; }
+ virtual bool is_metadata() const volatile { return true; }
virtual bool is_klass() const volatile { return false; }
virtual bool is_method() const volatile { return false; }
virtual bool is_methodData() const volatile { return false; }
From 132fd335ebbe3754b559cc5b2ba9c0c4f42f608d Mon Sep 17 00:00:00 2001
From: Vladimir Ivanov
Date: Tue, 4 Mar 2014 02:19:04 -0800
Subject: [PATCH 019/116] 8035887: VM crashes trying to force inlining the
recursive call
Reviewed-by: kvn, twisti
---
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 13 ++++++++-----
hotspot/src/share/vm/runtime/globals.hpp | 3 ++-
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
index 389eaf29b47..974bc04cc4d 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -3771,11 +3771,14 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
}
// now perform tests that are based on flag settings
- if (callee->force_inline()) {
- if (inline_level() > MaxForceInlineLevel) INLINE_BAILOUT("MaxForceInlineLevel");
- print_inlining(callee, "force inline by annotation");
- } else if (callee->should_inline()) {
- print_inlining(callee, "force inline by CompileOracle");
+ if (callee->force_inline() || callee->should_inline()) {
+ if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel");
+ if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep");
+
+ const char* msg = "";
+ if (callee->force_inline()) msg = "force inline by annotation";
+ if (callee->should_inline()) msg = "force inline by CompileOracle";
+ print_inlining(callee, msg);
} else {
// use heuristic controls on inlining
if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep");
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 866cff8349a..1d0f62ed4d7 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -2987,7 +2987,8 @@ class CommandLineFlags {
"maximum number of nested recursive calls that are inlined") \
\
develop(intx, MaxForceInlineLevel, 100, \
- "maximum number of nested @ForceInline calls that are inlined") \
+ "maximum number of nested calls that are forced for inlining " \
+ "(using CompilerOracle or marked w/ @ForceInline)") \
\
product_pd(intx, InlineSmallCode, \
"Only inline already compiled methods if their code size is " \
From 3ba019c8b2ec38b890dfa3b68dd89766356493f4 Mon Sep 17 00:00:00 2001
From: Vladimir Ivanov
Date: Tue, 4 Mar 2014 02:20:41 -0800
Subject: [PATCH 020/116] 8035828: Turn on @Stable support in VM
Reviewed-by: jrose, twisti
---
hotspot/src/share/vm/opto/c2_globals.hpp | 2 +-
hotspot/src/share/vm/runtime/globals.hpp | 4 +-
.../compiler/stable/TestStableBoolean.java | 627 +++++++++++++++++
.../test/compiler/stable/TestStableByte.java | 632 +++++++++++++++++
.../test/compiler/stable/TestStableChar.java | 631 +++++++++++++++++
.../compiler/stable/TestStableDouble.java | 632 +++++++++++++++++
.../test/compiler/stable/TestStableFloat.java | 632 +++++++++++++++++
.../test/compiler/stable/TestStableInt.java | 632 +++++++++++++++++
.../test/compiler/stable/TestStableLong.java | 632 +++++++++++++++++
.../compiler/stable/TestStableObject.java | 635 ++++++++++++++++++
.../test/compiler/stable/TestStableShort.java | 632 +++++++++++++++++
11 files changed, 5688 insertions(+), 3 deletions(-)
create mode 100644 hotspot/test/compiler/stable/TestStableBoolean.java
create mode 100644 hotspot/test/compiler/stable/TestStableByte.java
create mode 100644 hotspot/test/compiler/stable/TestStableChar.java
create mode 100644 hotspot/test/compiler/stable/TestStableDouble.java
create mode 100644 hotspot/test/compiler/stable/TestStableFloat.java
create mode 100644 hotspot/test/compiler/stable/TestStableInt.java
create mode 100644 hotspot/test/compiler/stable/TestStableLong.java
create mode 100644 hotspot/test/compiler/stable/TestStableObject.java
create mode 100644 hotspot/test/compiler/stable/TestStableShort.java
diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp
index cc5e2ced6b3..3064b2390f1 100644
--- a/hotspot/src/share/vm/opto/c2_globals.hpp
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp
@@ -452,7 +452,7 @@
product(bool, EliminateAutoBox, true, \
"Control optimizations for autobox elimination") \
\
- experimental(bool, UseImplicitStableValues, false, \
+ diagnostic(bool, UseImplicitStableValues, true, \
"Mark well-known stable fields as such (e.g. String.value)") \
\
product(intx, AutoBoxCacheMax, 128, \
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 1d0f62ed4d7..30f7007066d 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -3799,8 +3799,8 @@ class CommandLineFlags {
experimental(bool, TrustFinalNonStaticFields, false, \
"trust final non-static declarations for constant folding") \
\
- experimental(bool, FoldStableValues, false, \
- "Private flag to control optimizations for stable variables") \
+ diagnostic(bool, FoldStableValues, true, \
+ "Optimize loads from stable fields (marked w/ @Stable)") \
\
develop(bool, TraceInvokeDynamic, false, \
"trace internal invoke dynamic operations") \
diff --git a/hotspot/test/compiler/stable/TestStableBoolean.java b/hotspot/test/compiler/stable/TestStableBoolean.java
new file mode 100644
index 00000000000..37f42875022
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableBoolean.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableBoolean
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableBoolean.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableBoolean
+ * java/lang/invoke/TestStableBoolean$BooleanStable
+ * java/lang/invoke/TestStableBoolean$StaticBooleanStable
+ * java/lang/invoke/TestStableBoolean$VolatileBooleanStable
+ * java/lang/invoke/TestStableBoolean$BooleanArrayDim1
+ * java/lang/invoke/TestStableBoolean$BooleanArrayDim2
+ * java/lang/invoke/TestStableBoolean$BooleanArrayDim3
+ * java/lang/invoke/TestStableBoolean$BooleanArrayDim4
+ * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableBoolean$NestedStableField
+ * java/lang/invoke/TestStableBoolean$NestedStableField$A
+ * java/lang/invoke/TestStableBoolean$NestedStableField1
+ * java/lang/invoke/TestStableBoolean$NestedStableField1$A
+ * java/lang/invoke/TestStableBoolean$NestedStableField2
+ * java/lang/invoke/TestStableBoolean$NestedStableField2$A
+ * java/lang/invoke/TestStableBoolean$NestedStableField3
+ * java/lang/invoke/TestStableBoolean$NestedStableField3$A
+ * java/lang/invoke/TestStableBoolean$DefaultValue
+ * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableBoolean
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableBoolean
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableBoolean
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableBoolean
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableBoolean {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(BooleanStable.class);
+ run(StaticBooleanStable.class);
+ run(VolatileBooleanStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(BooleanArrayDim1.class);
+ run(BooleanArrayDim2.class);
+ run(BooleanArrayDim3.class);
+ run(BooleanArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable boolean v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static boolean get() { return c.v; }
+ public static void test() throws Exception {
+ boolean val1 = get();
+ c.v = true; boolean val2 = get();
+ assertEquals(val1, false);
+ assertEquals(val2, true);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class BooleanStable {
+ public @Stable boolean v;
+
+ public static final BooleanStable c = new BooleanStable();
+ public static boolean get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = true; boolean val1 = get();
+ c.v = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticBooleanStable {
+ public static @Stable boolean v;
+
+ public static final StaticBooleanStable c = new StaticBooleanStable();
+ public static boolean get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = true; boolean val1 = get();
+ c.v = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileBooleanStable {
+ public @Stable volatile boolean v;
+
+ public static final VolatileBooleanStable c = new VolatileBooleanStable();
+ public static boolean get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = true; boolean val1 = get();
+ c.v = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class BooleanArrayDim1 {
+ public @Stable boolean[] v;
+
+ public static final BooleanArrayDim1 c = new BooleanArrayDim1();
+ public static boolean get() { return c.v[0]; }
+ public static boolean get1() { return c.v[10]; }
+ public static boolean[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1]; c.v[0] = true; boolean val1 = get();
+ c.v[0] = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ }
+
+ {
+ c.v = new boolean[20]; c.v[10] = true; boolean val1 = get1();
+ c.v[10] = false; boolean val2 = get1();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ }
+
+ {
+ c.v = new boolean[1]; boolean[] val1 = get2();
+ c.v = new boolean[1]; boolean[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class BooleanArrayDim2 {
+ public @Stable boolean[][] v;
+
+ public static final BooleanArrayDim2 c = new BooleanArrayDim2();
+ public static boolean get() { return c.v[0][0]; }
+ public static boolean[] get1() { return c.v[0]; }
+ public static boolean[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1][1]; c.v[0][0] = true; boolean val1 = get();
+ c.v[0][0] = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+
+ c.v = new boolean[1][1]; c.v[0][0] = false; boolean val3 = get();
+ assertEquals(val3, (isStableEnabled ? true : false));
+
+ c.v[0] = new boolean[1]; c.v[0][0] = false; boolean val4 = get();
+ assertEquals(val4, (isStableEnabled ? true : false));
+ }
+
+ {
+ c.v = new boolean[1][1]; boolean[] val1 = get1();
+ c.v[0] = new boolean[1]; boolean[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1]; boolean[][] val1 = get2();
+ c.v = new boolean[1][1]; boolean[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class BooleanArrayDim3 {
+ public @Stable boolean[][][] v;
+
+ public static final BooleanArrayDim3 c = new BooleanArrayDim3();
+ public static boolean get() { return c.v[0][0][0]; }
+ public static boolean[] get1() { return c.v[0][0]; }
+ public static boolean[][] get2() { return c.v[0]; }
+ public static boolean[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1][1][1]; c.v[0][0][0] = true; boolean val1 = get();
+ c.v[0][0][0] = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+
+ c.v = new boolean[1][1][1]; c.v[0][0][0] = false; boolean val3 = get();
+ assertEquals(val3, (isStableEnabled ? true : false));
+
+ c.v[0] = new boolean[1][1]; c.v[0][0][0] = false; boolean val4 = get();
+ assertEquals(val4, (isStableEnabled ? true : false));
+
+ c.v[0][0] = new boolean[1]; c.v[0][0][0] = false; boolean val5 = get();
+ assertEquals(val5, (isStableEnabled ? true : false));
+ }
+
+ {
+ c.v = new boolean[1][1][1]; boolean[] val1 = get1();
+ c.v[0][0] = new boolean[1]; boolean[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1]; boolean[][] val1 = get2();
+ c.v[0] = new boolean[1][1]; boolean[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1]; boolean[][][] val1 = get3();
+ c.v = new boolean[1][1][1]; boolean[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class BooleanArrayDim4 {
+ public @Stable boolean[][][][] v;
+
+ public static final BooleanArrayDim4 c = new BooleanArrayDim4();
+ public static boolean get() { return c.v[0][0][0][0]; }
+ public static boolean[] get1() { return c.v[0][0][0]; }
+ public static boolean[][] get2() { return c.v[0][0]; }
+ public static boolean[][][] get3() { return c.v[0]; }
+ public static boolean[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = true; boolean val1 = get();
+ c.v[0][0][0][0] = false; boolean val2 = get();
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+
+ c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = false; boolean val3 = get();
+ assertEquals(val3, (isStableEnabled ? true : false));
+
+ c.v[0] = new boolean[1][1][1]; c.v[0][0][0][0] = false; boolean val4 = get();
+ assertEquals(val4, (isStableEnabled ? true : false));
+
+ c.v[0][0] = new boolean[1][1]; c.v[0][0][0][0] = false; boolean val5 = get();
+ assertEquals(val5, (isStableEnabled ? true : false));
+
+ c.v[0][0][0] = new boolean[1]; c.v[0][0][0][0] = false; boolean val6 = get();
+ assertEquals(val6, (isStableEnabled ? true : false));
+ }
+
+ {
+ c.v = new boolean[1][1][1][1]; boolean[] val1 = get1();
+ c.v[0][0][0] = new boolean[1]; boolean[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1][1]; boolean[][] val1 = get2();
+ c.v[0][0] = new boolean[1][1]; boolean[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1][1]; boolean[][][] val1 = get3();
+ c.v[0] = new boolean[1][1][1]; boolean[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1][1]; boolean[][][][] val1 = get4();
+ c.v = new boolean[1][1][1][1]; boolean[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static boolean get() { return ((boolean[])c.v)[0]; }
+ public static boolean[] get1() { return (boolean[])c.v; }
+ public static boolean[] get2() { return (boolean[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1]; ((boolean[])c.v)[0] = true; boolean val1 = get();
+ ((boolean[])c.v)[0] = false; boolean val2 = get();
+
+ assertEquals(val1, true);
+ assertEquals(val2, false);
+ }
+
+ {
+ c.v = new boolean[1]; boolean[] val1 = get1();
+ c.v = new boolean[1]; boolean[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static boolean get() { return ((boolean[][])c.v)[0][0]; }
+ public static boolean[] get1() { return (boolean[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1][1]; ((boolean[][])c.v)[0][0] = true; boolean val1 = get();
+ ((boolean[][])c.v)[0][0] = false; boolean val2 = get();
+
+ assertEquals(val1, true);
+ assertEquals(val2, false);
+ }
+
+ {
+ c.v = new boolean[1][1]; c.v[0] = new boolean[0]; boolean[] val1 = get1();
+ c.v[0] = new boolean[0]; boolean[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[0][0]; Object[] val1 = get2();
+ c.v = new boolean[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static boolean get() { return ((boolean[][][])c.v)[0][0][0]; }
+ public static boolean[] get1() { return (boolean[])(c.v[0][0]); }
+ public static boolean[][] get2() { return (boolean[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new boolean[1][1][1]; ((boolean[][][])c.v)[0][0][0] = true; boolean val1 = get();
+ ((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get();
+
+ assertEquals(val1, true);
+ assertEquals(val2, false);
+ }
+
+ {
+ c.v = new boolean[1][1][1]; c.v[0][0] = new boolean[0]; boolean[] val1 = get1();
+ c.v[0][0] = new boolean[0]; boolean[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[1][1][1]; c.v[0] = new boolean[0][0]; boolean[][] val1 = get2();
+ c.v[0] = new boolean[0][0]; boolean[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new boolean[0][0][0]; Object[][] val1 = get3();
+ c.v = new boolean[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable boolean a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static boolean get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = true; A val1 = get();
+ c.v.a = false; A val2 = get();
+
+ assertEquals(val1.a, false);
+ assertEquals(val2.a, false);
+ }
+
+ {
+ c.v = new A(); c.v.a = true; boolean val1 = get1();
+ c.v.a = false; boolean val2 = get1();
+ c.v = new A(); c.v.a = false; boolean val3 = get1();
+
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ assertEquals(val3, (isStableEnabled ? true : false));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable boolean a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static boolean get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = true; c.v.next.a = true; A val1 = get();
+ c.v.a = false; c.v.next.a = false; A val2 = get();
+
+ assertEquals(val1.a, false);
+ assertEquals(val2.a, false);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = true; boolean val1 = get1();
+ c.v.a = false; boolean val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = false; boolean val3 = get1();
+
+ assertEquals(val1, true);
+ assertEquals(val2, (isStableEnabled ? true : false));
+ assertEquals(val3, (isStableEnabled ? true : false));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable boolean a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static boolean get() { return c.v.left.left.left.a; }
+ public static boolean get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = true; boolean val1 = get(); boolean val2 = get1();
+ c.v.a = false; boolean val3 = get(); boolean val4 = get1();
+
+ assertEquals(val1, true);
+ assertEquals(val3, (isStableEnabled ? true : false));
+
+ assertEquals(val2, true);
+ assertEquals(val4, false);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable boolean a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static boolean get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static boolean get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = true; boolean val1 = get(); boolean val2 = get1();
+ elem.a = false; boolean val3 = get(); boolean val4 = get1();
+
+ assertEquals(val1, true);
+ assertEquals(val3, (isStableEnabled ? true : false));
+
+ assertEquals(val2, true);
+ assertEquals(val4, false);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(boolean i, boolean j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableByte.java b/hotspot/test/compiler/stable/TestStableByte.java
new file mode 100644
index 00000000000..4a14fcc3b2f
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableByte.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableByte
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableByte.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableByte
+ * java/lang/invoke/TestStableByte$ByteStable
+ * java/lang/invoke/TestStableByte$StaticByteStable
+ * java/lang/invoke/TestStableByte$VolatileByteStable
+ * java/lang/invoke/TestStableByte$ByteArrayDim1
+ * java/lang/invoke/TestStableByte$ByteArrayDim2
+ * java/lang/invoke/TestStableByte$ByteArrayDim3
+ * java/lang/invoke/TestStableByte$ByteArrayDim4
+ * java/lang/invoke/TestStableByte$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableByte$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableByte$NestedStableField
+ * java/lang/invoke/TestStableByte$NestedStableField$A
+ * java/lang/invoke/TestStableByte$NestedStableField1
+ * java/lang/invoke/TestStableByte$NestedStableField1$A
+ * java/lang/invoke/TestStableByte$NestedStableField2
+ * java/lang/invoke/TestStableByte$NestedStableField2$A
+ * java/lang/invoke/TestStableByte$NestedStableField3
+ * java/lang/invoke/TestStableByte$NestedStableField3$A
+ * java/lang/invoke/TestStableByte$DefaultValue
+ * java/lang/invoke/TestStableByte$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableByte
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableByte
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableByte
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableByte
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableByte {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(ByteStable.class);
+ run(StaticByteStable.class);
+ run(VolatileByteStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(ByteArrayDim1.class);
+ run(ByteArrayDim2.class);
+ run(ByteArrayDim3.class);
+ run(ByteArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable byte v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static byte get() { return c.v; }
+ public static void test() throws Exception {
+ byte val1 = get();
+ c.v = 1; byte val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 1);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ByteStable {
+ public @Stable byte v;
+
+ public static final ByteStable c = new ByteStable();
+ public static byte get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; byte val1 = get();
+ c.v = 127; byte val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : 127));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticByteStable {
+ public static @Stable byte v;
+
+ public static final StaticByteStable c = new StaticByteStable();
+ public static byte get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; byte val1 = get();
+ c.v = 127; byte val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : 127));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileByteStable {
+ public @Stable volatile byte v;
+
+ public static final VolatileByteStable c = new VolatileByteStable();
+ public static byte get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; byte val1 = get();
+ c.v = 127; byte val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : 127));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class ByteArrayDim1 {
+ public @Stable byte[] v;
+
+ public static final ByteArrayDim1 c = new ByteArrayDim1();
+ public static byte get() { return c.v[0]; }
+ public static byte get1() { return c.v[10]; }
+ public static byte[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1]; c.v[0] = 1; byte val1 = get();
+ c.v[0] = 2; byte val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new byte[1]; c.v[0] = 3; byte val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new byte[20]; c.v[10] = 1; byte val1 = get1();
+ c.v[10] = 2; byte val2 = get1();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new byte[20]; c.v[10] = 3; byte val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new byte[1]; byte[] val1 = get2();
+ c.v = new byte[1]; byte[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ByteArrayDim2 {
+ public @Stable byte[][] v;
+
+ public static final ByteArrayDim2 c = new ByteArrayDim2();
+ public static byte get() { return c.v[0][0]; }
+ public static byte[] get1() { return c.v[0]; }
+ public static byte[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1][1]; c.v[0][0] = 1; byte val1 = get();
+ c.v[0][0] = 2; byte val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new byte[1][1]; c.v[0][0] = 3; byte val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new byte[1]; c.v[0][0] = 4; byte val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+ }
+
+ {
+ c.v = new byte[1][1]; byte[] val1 = get1();
+ c.v[0] = new byte[1]; byte[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1]; byte[][] val1 = get2();
+ c.v = new byte[1][1]; byte[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ByteArrayDim3 {
+ public @Stable byte[][][] v;
+
+ public static final ByteArrayDim3 c = new ByteArrayDim3();
+ public static byte get() { return c.v[0][0][0]; }
+ public static byte[] get1() { return c.v[0][0]; }
+ public static byte[][] get2() { return c.v[0]; }
+ public static byte[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1][1][1]; c.v[0][0][0] = 1; byte val1 = get();
+ c.v[0][0][0] = 2; byte val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new byte[1][1][1]; c.v[0][0][0] = 3; byte val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new byte[1][1]; c.v[0][0][0] = 4; byte val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new byte[1]; c.v[0][0][0] = 5; byte val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+ }
+
+ {
+ c.v = new byte[1][1][1]; byte[] val1 = get1();
+ c.v[0][0] = new byte[1]; byte[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1]; byte[][] val1 = get2();
+ c.v[0] = new byte[1][1]; byte[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1]; byte[][][] val1 = get3();
+ c.v = new byte[1][1][1]; byte[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ByteArrayDim4 {
+ public @Stable byte[][][][] v;
+
+ public static final ByteArrayDim4 c = new ByteArrayDim4();
+ public static byte get() { return c.v[0][0][0][0]; }
+ public static byte[] get1() { return c.v[0][0][0]; }
+ public static byte[][] get2() { return c.v[0][0]; }
+ public static byte[][][] get3() { return c.v[0]; }
+ public static byte[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 1; byte val1 = get();
+ c.v[0][0][0][0] = 2; byte val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 3; byte val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new byte[1][1][1]; c.v[0][0][0][0] = 4; byte val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new byte[1][1]; c.v[0][0][0][0] = 5; byte val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+
+ c.v[0][0][0] = new byte[1]; c.v[0][0][0][0] = 6; byte val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1 : 6));
+ }
+
+ {
+ c.v = new byte[1][1][1][1]; byte[] val1 = get1();
+ c.v[0][0][0] = new byte[1]; byte[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1][1]; byte[][] val1 = get2();
+ c.v[0][0] = new byte[1][1]; byte[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1][1]; byte[][][] val1 = get3();
+ c.v[0] = new byte[1][1][1]; byte[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1][1]; byte[][][][] val1 = get4();
+ c.v = new byte[1][1][1][1]; byte[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static byte get() { return ((byte[])c.v)[0]; }
+ public static byte[] get1() { return (byte[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1]; ((byte[])c.v)[0] = 1; byte val1 = get();
+ ((byte[])c.v)[0] = 2; byte val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new byte[1]; byte[] val1 = get1();
+ c.v = new byte[1]; byte[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static byte get() { return ((byte[][])c.v)[0][0]; }
+ public static byte[] get1() { return (byte[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1][1]; ((byte[][])c.v)[0][0] = 1; byte val1 = get();
+ ((byte[][])c.v)[0][0] = 2; byte val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new byte[1][1]; c.v[0] = new byte[0]; byte[] val1 = get1();
+ c.v[0] = new byte[0]; byte[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[0][0]; Object[] val1 = get2();
+ c.v = new byte[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static byte get() { return ((byte[][][])c.v)[0][0][0]; }
+ public static byte[] get1() { return (byte[])(c.v[0][0]); }
+ public static byte[][] get2() { return (byte[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new byte[1][1][1]; ((byte[][][])c.v)[0][0][0] = 1; byte val1 = get();
+ ((byte[][][])c.v)[0][0][0] = 2; byte val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new byte[1][1][1]; c.v[0][0] = new byte[0]; byte[] val1 = get1();
+ c.v[0][0] = new byte[0]; byte[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[1][1][1]; c.v[0] = new byte[0][0]; byte[][] val1 = get2();
+ c.v[0] = new byte[0][0]; byte[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new byte[0][0][0]; Object[][] val1 = get3();
+ c.v = new byte[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable byte a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static byte get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1; A val1 = get();
+ c.v.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1; byte val1 = get1();
+ c.v.a = 2; byte val2 = get1();
+ c.v = new A(); c.v.a = 3; byte val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable byte a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static byte get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1; c.v.next.a = 1; A val1 = get();
+ c.v.a = 2; c.v.next.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1; byte val1 = get1();
+ c.v.a = 2; byte val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3; byte val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable byte a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static byte get() { return c.v.left.left.left.a; }
+ public static byte get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1; byte val1 = get(); byte val2 = get1();
+ c.v.a = 2; byte val3 = get(); byte val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable byte a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static byte get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static byte get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1; byte val1 = get(); byte val2 = get1();
+ elem.a = 2; byte val3 = get(); byte val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableChar.java b/hotspot/test/compiler/stable/TestStableChar.java
new file mode 100644
index 00000000000..ede8e9a4df7
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableChar.java
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableChar
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableChar.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableChar
+ * java/lang/invoke/TestStableChar$CharStable
+ * java/lang/invoke/TestStableChar$StaticCharStable
+ * java/lang/invoke/TestStableChar$VolatileCharStable
+ * java/lang/invoke/TestStableChar$CharArrayDim1
+ * java/lang/invoke/TestStableChar$CharArrayDim2
+ * java/lang/invoke/TestStableChar$CharArrayDim3
+ * java/lang/invoke/TestStableChar$CharArrayDim4
+ * java/lang/invoke/TestStableChar$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableChar$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableChar$NestedStableField
+ * java/lang/invoke/TestStableChar$NestedStableField$A
+ * java/lang/invoke/TestStableChar$NestedStableField1
+ * java/lang/invoke/TestStableChar$NestedStableField1$A
+ * java/lang/invoke/TestStableChar$NestedStableField2
+ * java/lang/invoke/TestStableChar$NestedStableField2$A
+ * java/lang/invoke/TestStableChar$NestedStableField3
+ * java/lang/invoke/TestStableChar$NestedStableField3$A
+ * java/lang/invoke/TestStableChar$DefaultValue
+ * java/lang/invoke/TestStableChar$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableChar
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableChar
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableChar
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableChar
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableChar {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(CharStable.class);
+ run(StaticCharStable.class);
+ run(VolatileCharStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(CharArrayDim1.class);
+ run(CharArrayDim2.class);
+ run(CharArrayDim3.class);
+ run(CharArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable char v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static char get() { return c.v; }
+ public static void test() throws Exception {
+ char val1 = get();
+ c.v = 'a'; char val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 'a');
+ }
+ }
+
+ /* ==================================================== */
+
+ static class CharStable {
+ public @Stable char v;
+
+ public static final CharStable c = new CharStable();
+ public static char get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 'a'; char val1 = get();
+ c.v = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticCharStable {
+ public @Stable char v;
+
+ public static final StaticCharStable c = new StaticCharStable();
+ public static char get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 'a'; char val1 = get();
+ c.v = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileCharStable {
+ public @Stable volatile char v;
+
+ public static final VolatileCharStable c = new VolatileCharStable();
+ public static char get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 'a'; char val1 = get();
+ c.v = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class CharArrayDim1 {
+ public @Stable char[] v;
+
+ public static final CharArrayDim1 c = new CharArrayDim1();
+ public static char get() { return c.v[0]; }
+ public static char get1() { return c.v[10]; }
+ public static char[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new char[1]; c.v[0] = 'a'; char val1 = get();
+ c.v[0] = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+
+ c.v = new char[1]; c.v[0] = 'c'; char val3 = get();
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+ }
+
+ {
+ c.v = new char[20]; c.v[10] = 'a'; char val1 = get1();
+ c.v[10] = 'b'; char val2 = get1();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+
+ c.v = new char[20]; c.v[10] = 'c'; char val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+ }
+
+ {
+ c.v = new char[1]; char[] val1 = get2();
+ c.v = new char[1]; char[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class CharArrayDim2 {
+ public @Stable char[][] v;
+
+ public static final CharArrayDim2 c = new CharArrayDim2();
+ public static char get() { return c.v[0][0]; }
+ public static char[] get1() { return c.v[0]; }
+ public static char[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new char[1][1]; c.v[0][0] = 'a'; char val1 = get();
+ c.v[0][0] = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+
+ c.v = new char[1][1]; c.v[0][0] = 'c'; char val3 = get();
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+
+ c.v[0] = new char[1]; c.v[0][0] = 'd'; char val4 = get();
+ assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
+ }
+
+ {
+ c.v = new char[1][1]; char[] val1 = get1();
+ c.v[0] = new char[1]; char[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1]; char[][] val1 = get2();
+ c.v = new char[1][1]; char[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class CharArrayDim3 {
+ public @Stable char[][][] v;
+
+ public static final CharArrayDim3 c = new CharArrayDim3();
+ public static char get() { return c.v[0][0][0]; }
+ public static char[] get1() { return c.v[0][0]; }
+ public static char[][] get2() { return c.v[0]; }
+ public static char[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new char[1][1][1]; c.v[0][0][0] = 'a'; char val1 = get();
+ c.v[0][0][0] = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+
+ c.v = new char[1][1][1]; c.v[0][0][0] = 'c'; char val3 = get();
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+
+ c.v[0] = new char[1][1]; c.v[0][0][0] = 'd'; char val4 = get();
+ assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
+
+ c.v[0][0] = new char[1]; c.v[0][0][0] = 'e'; char val5 = get();
+ assertEquals(val5, (isStableEnabled ? 'a' : 'e'));
+ }
+
+ {
+ c.v = new char[1][1][1]; char[] val1 = get1();
+ c.v[0][0] = new char[1]; char[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1]; char[][] val1 = get2();
+ c.v[0] = new char[1][1]; char[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1]; char[][][] val1 = get3();
+ c.v = new char[1][1][1]; char[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class CharArrayDim4 {
+ public @Stable char[][][][] v;
+
+ public static final CharArrayDim4 c = new CharArrayDim4();
+ public static char get() { return c.v[0][0][0][0]; }
+ public static char[] get1() { return c.v[0][0][0]; }
+ public static char[][] get2() { return c.v[0][0]; }
+ public static char[][][] get3() { return c.v[0]; }
+ public static char[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'a'; char val1 = get();
+ c.v[0][0][0][0] = 'b'; char val2 = get();
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+
+ c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'c'; char val3 = get();
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+
+ c.v[0] = new char[1][1][1]; c.v[0][0][0][0] = 'd'; char val4 = get();
+ assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
+
+ c.v[0][0] = new char[1][1]; c.v[0][0][0][0] = 'e'; char val5 = get();
+ assertEquals(val5, (isStableEnabled ? 'a' : 'e'));
+
+ c.v[0][0][0] = new char[1]; c.v[0][0][0][0] = 'f'; char val6 = get();
+ assertEquals(val6, (isStableEnabled ? 'a' : 'f'));
+ }
+
+ {
+ c.v = new char[1][1][1][1]; char[] val1 = get1();
+ c.v[0][0][0] = new char[1]; char[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1][1]; char[][] val1 = get2();
+ c.v[0][0] = new char[1][1]; char[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1][1]; char[][][] val1 = get3();
+ c.v[0] = new char[1][1][1]; char[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1][1]; char[][][][] val1 = get4();
+ c.v = new char[1][1][1][1]; char[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static char get() { return ((char[])c.v)[0]; }
+ public static char[] get1() { return (char[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new char[1]; ((char[])c.v)[0] = 'a'; char val1 = get();
+ ((char[])c.v)[0] = 'b'; char val2 = get();
+
+ assertEquals(val1, 'a');
+ assertEquals(val2, 'b');
+ }
+
+ {
+ c.v = new char[1]; char[] val1 = get1();
+ c.v = new char[1]; char[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static char get() { return ((char[][])c.v)[0][0]; }
+ public static char[] get1() { return (char[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new char[1][1]; ((char[][])c.v)[0][0] = 'a'; char val1 = get();
+ ((char[][])c.v)[0][0] = 'b'; char val2 = get();
+
+ assertEquals(val1, 'a');
+ assertEquals(val2, 'b');
+ }
+
+ {
+ c.v = new char[1][1]; c.v[0] = new char[0]; char[] val1 = get1();
+ c.v[0] = new char[0]; char[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[0][0]; Object[] val1 = get2();
+ c.v = new char[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static char get() { return ((char[][][])c.v)[0][0][0]; }
+ public static char[] get1() { return (char[])(c.v[0][0]); }
+ public static char[][] get2() { return (char[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new char[1][1][1]; ((char[][][])c.v)[0][0][0] = 'a'; char val1 = get();
+ ((char[][][])c.v)[0][0][0] = 'b'; char val2 = get();
+
+ assertEquals(val1, 'a');
+ assertEquals(val2, 'b');
+ }
+
+ {
+ c.v = new char[1][1][1]; c.v[0][0] = new char[0]; char[] val1 = get1();
+ c.v[0][0] = new char[0]; char[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[1][1][1]; c.v[0] = new char[0][0]; char[][] val1 = get2();
+ c.v[0] = new char[0][0]; char[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new char[0][0][0]; Object[][] val1 = get3();
+ c.v = new char[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable char a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static char get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 'a'; A val1 = get();
+ c.v.a = 'b'; A val2 = get();
+
+ assertEquals(val1.a, 'b');
+ assertEquals(val2.a, 'b');
+ }
+
+ {
+ c.v = new A(); c.v.a = 'a'; char val1 = get1();
+ c.v.a = 'b'; char val2 = get1();
+ c.v = new A(); c.v.a = 'c'; char val3 = get1();
+
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable char a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static char get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get();
+ c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get();
+
+ assertEquals(val1.a, 'b');
+ assertEquals(val2.a, 'b');
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 'a'; char val1 = get1();
+ c.v.a = 'b'; char val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 'c'; char val3 = get1();
+
+ assertEquals(val1, 'a');
+ assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
+ assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable char a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static char get() { return c.v.left.left.left.a; }
+ public static char get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 'a'; char val1 = get(); char val2 = get1();
+ c.v.a = 'b'; char val3 = get(); char val4 = get1();
+
+ assertEquals(val1, 'a');
+ assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
+
+ assertEquals(val2, 'a');
+ assertEquals(val4, 'b');
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable char a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static char get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static char get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 'a'; char val1 = get(); char val2 = get1();
+ elem.a = 'b'; char val3 = get(); char val4 = get1();
+
+ assertEquals(val1, 'a');
+ assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
+
+ assertEquals(val2, 'a');
+ assertEquals(val4, 'b');
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableDouble.java b/hotspot/test/compiler/stable/TestStableDouble.java
new file mode 100644
index 00000000000..b656acbd1ae
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableDouble.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableDouble
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableDouble.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableDouble
+ * java/lang/invoke/TestStableDouble$DoubleStable
+ * java/lang/invoke/TestStableDouble$StaticDoubleStable
+ * java/lang/invoke/TestStableDouble$VolatileDoubleStable
+ * java/lang/invoke/TestStableDouble$DoubleArrayDim1
+ * java/lang/invoke/TestStableDouble$DoubleArrayDim2
+ * java/lang/invoke/TestStableDouble$DoubleArrayDim3
+ * java/lang/invoke/TestStableDouble$DoubleArrayDim4
+ * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableDouble$NestedStableField
+ * java/lang/invoke/TestStableDouble$NestedStableField$A
+ * java/lang/invoke/TestStableDouble$NestedStableField1
+ * java/lang/invoke/TestStableDouble$NestedStableField1$A
+ * java/lang/invoke/TestStableDouble$NestedStableField2
+ * java/lang/invoke/TestStableDouble$NestedStableField2$A
+ * java/lang/invoke/TestStableDouble$NestedStableField3
+ * java/lang/invoke/TestStableDouble$NestedStableField3$A
+ * java/lang/invoke/TestStableDouble$DefaultValue
+ * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableDouble
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableDouble
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableDouble
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableDouble
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableDouble {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(DoubleStable.class);
+ run(StaticDoubleStable.class);
+ run(VolatileDoubleStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(DoubleArrayDim1.class);
+ run(DoubleArrayDim2.class);
+ run(DoubleArrayDim3.class);
+ run(DoubleArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable double v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static double get() { return c.v; }
+ public static void test() throws Exception {
+ double val1 = get();
+ c.v = 1.0; double val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 1.0);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DoubleStable {
+ public @Stable double v;
+
+ public static final DoubleStable c = new DoubleStable();
+ public static double get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0; double val1 = get();
+ c.v = Double.MAX_VALUE; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticDoubleStable {
+ public static @Stable double v;
+
+ public static final StaticDoubleStable c = new StaticDoubleStable();
+ public static double get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0; double val1 = get();
+ c.v = Double.MAX_VALUE; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileDoubleStable {
+ public @Stable double v;
+
+ public static final VolatileDoubleStable c = new VolatileDoubleStable();
+ public static double get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0; double val1 = get();
+ c.v = Double.MAX_VALUE; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class DoubleArrayDim1 {
+ public @Stable double[] v;
+
+ public static final DoubleArrayDim1 c = new DoubleArrayDim1();
+ public static double get() { return c.v[0]; }
+ public static double get1() { return c.v[10]; }
+ public static double[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new double[1]; c.v[0] = 1.0; double val1 = get();
+ c.v[0] = 2.0; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+
+ c.v = new double[1]; c.v[0] = 3.0; double val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+ }
+
+ {
+ c.v = new double[20]; c.v[10] = 1.0; double val1 = get1();
+ c.v[10] = 2.0; double val2 = get1();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+
+ c.v = new double[20]; c.v[10] = 3.0; double val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+ }
+
+ {
+ c.v = new double[1]; double[] val1 = get2();
+ c.v = new double[1]; double[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DoubleArrayDim2 {
+ public @Stable double[][] v;
+
+ public static final DoubleArrayDim2 c = new DoubleArrayDim2();
+ public static double get() { return c.v[0][0]; }
+ public static double[] get1() { return c.v[0]; }
+ public static double[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new double[1][1]; c.v[0][0] = 1.0; double val1 = get();
+ c.v[0][0] = 2.0; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+
+ c.v = new double[1][1]; c.v[0][0] = 3.0; double val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+
+ c.v[0] = new double[1]; c.v[0][0] = 4.0; double val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
+ }
+
+ {
+ c.v = new double[1][1]; double[] val1 = get1();
+ c.v[0] = new double[1]; double[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1]; double[][] val1 = get2();
+ c.v = new double[1][1]; double[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DoubleArrayDim3 {
+ public @Stable double[][][] v;
+
+ public static final DoubleArrayDim3 c = new DoubleArrayDim3();
+ public static double get() { return c.v[0][0][0]; }
+ public static double[] get1() { return c.v[0][0]; }
+ public static double[][] get2() { return c.v[0]; }
+ public static double[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new double[1][1][1]; c.v[0][0][0] = 1.0; double val1 = get();
+ c.v[0][0][0] = 2.0; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+
+ c.v = new double[1][1][1]; c.v[0][0][0] = 3.0; double val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+
+ c.v[0] = new double[1][1]; c.v[0][0][0] = 4.0; double val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
+
+ c.v[0][0] = new double[1]; c.v[0][0][0] = 5.0; double val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1.0 : 5.0));
+ }
+
+ {
+ c.v = new double[1][1][1]; double[] val1 = get1();
+ c.v[0][0] = new double[1]; double[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1]; double[][] val1 = get2();
+ c.v[0] = new double[1][1]; double[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1]; double[][][] val1 = get3();
+ c.v = new double[1][1][1]; double[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DoubleArrayDim4 {
+ public @Stable double[][][][] v;
+
+ public static final DoubleArrayDim4 c = new DoubleArrayDim4();
+ public static double get() { return c.v[0][0][0][0]; }
+ public static double[] get1() { return c.v[0][0][0]; }
+ public static double[][] get2() { return c.v[0][0]; }
+ public static double[][][] get3() { return c.v[0]; }
+ public static double[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 1.0; double val1 = get();
+ c.v[0][0][0][0] = 2.0; double val2 = get();
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+
+ c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 3.0; double val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+
+ c.v[0] = new double[1][1][1]; c.v[0][0][0][0] = 4.0; double val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
+
+ c.v[0][0] = new double[1][1]; c.v[0][0][0][0] = 5.0; double val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1.0 : 5.0));
+
+ c.v[0][0][0] = new double[1]; c.v[0][0][0][0] = 6.0; double val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1.0 : 6.0));
+ }
+
+ {
+ c.v = new double[1][1][1][1]; double[] val1 = get1();
+ c.v[0][0][0] = new double[1]; double[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1][1]; double[][] val1 = get2();
+ c.v[0][0] = new double[1][1]; double[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1][1]; double[][][] val1 = get3();
+ c.v[0] = new double[1][1][1]; double[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1][1]; double[][][][] val1 = get4();
+ c.v = new double[1][1][1][1]; double[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static double get() { return ((double[])c.v)[0]; }
+ public static double[] get1() { return (double[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new double[1]; ((double[])c.v)[0] = 1.0; double val1 = get();
+ ((double[])c.v)[0] = 2.0; double val2 = get();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val2, 2.0);
+ }
+
+ {
+ c.v = new double[1]; double[] val1 = get1();
+ c.v = new double[1]; double[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static double get() { return ((double[][])c.v)[0][0]; }
+ public static double[] get1() { return (double[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new double[1][1]; ((double[][])c.v)[0][0] = 1.0; double val1 = get();
+ ((double[][])c.v)[0][0] = 2.0; double val2 = get();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val2, 2.0);
+ }
+
+ {
+ c.v = new double[1][1]; c.v[0] = new double[0]; double[] val1 = get1();
+ c.v[0] = new double[0]; double[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[0][0]; Object[] val1 = get2();
+ c.v = new double[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static double get() { return ((double[][][])c.v)[0][0][0]; }
+ public static double[] get1() { return (double[])(c.v[0][0]); }
+ public static double[][] get2() { return (double[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new double[1][1][1]; ((double[][][])c.v)[0][0][0] = 1.0; double val1 = get();
+ ((double[][][])c.v)[0][0][0] = 2.0; double val2 = get();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val2, 2.0);
+ }
+
+ {
+ c.v = new double[1][1][1]; c.v[0][0] = new double[0]; double[] val1 = get1();
+ c.v[0][0] = new double[0]; double[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[1][1][1]; c.v[0] = new double[0][0]; double[][] val1 = get2();
+ c.v[0] = new double[0][0]; double[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new double[0][0][0]; Object[][] val1 = get3();
+ c.v = new double[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable double a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static double get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1.0; A val1 = get();
+ c.v.a = 2.0; A val2 = get();
+
+ assertEquals(val1.a, 2.0);
+ assertEquals(val2.a, 2.0);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1.0; double val1 = get1();
+ c.v.a = 2.0; double val2 = get1();
+ c.v = new A(); c.v.a = 3.0; double val3 = get1();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable double a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static double get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1.0; c.v.next.a = 1.0; A val1 = get();
+ c.v.a = 2.0; c.v.next.a = 2.0; A val2 = get();
+
+ assertEquals(val1.a, 2.0);
+ assertEquals(val2.a, 2.0);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1.0; double val1 = get1();
+ c.v.a = 2.0; double val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3.0; double val3 = get1();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
+ assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable double a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static double get() { return c.v.left.left.left.a; }
+ public static double get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1.0; double val1 = get(); double val2 = get1();
+ c.v.a = 2.0; double val3 = get(); double val4 = get1();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val3, (isStableEnabled ? 1.0 : 2.0));
+
+ assertEquals(val2, 1.0);
+ assertEquals(val4, 2.0);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable double a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static double get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static double get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1.0; double val1 = get(); double val2 = get1();
+ elem.a = 2.0; double val3 = get(); double val4 = get1();
+
+ assertEquals(val1, 1.0);
+ assertEquals(val3, (isStableEnabled ? 1.0 : 2.0));
+
+ assertEquals(val2, 1.0);
+ assertEquals(val4, 2.0);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(double i, double j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableFloat.java b/hotspot/test/compiler/stable/TestStableFloat.java
new file mode 100644
index 00000000000..ab1c3f0be1f
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableFloat.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableFloat
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableFloat.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableFloat
+ * java/lang/invoke/TestStableFloat$FloatStable
+ * java/lang/invoke/TestStableFloat$StaticFloatStable
+ * java/lang/invoke/TestStableFloat$VolatileFloatStable
+ * java/lang/invoke/TestStableFloat$FloatArrayDim1
+ * java/lang/invoke/TestStableFloat$FloatArrayDim2
+ * java/lang/invoke/TestStableFloat$FloatArrayDim3
+ * java/lang/invoke/TestStableFloat$FloatArrayDim4
+ * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableFloat$NestedStableField
+ * java/lang/invoke/TestStableFloat$NestedStableField$A
+ * java/lang/invoke/TestStableFloat$NestedStableField1
+ * java/lang/invoke/TestStableFloat$NestedStableField1$A
+ * java/lang/invoke/TestStableFloat$NestedStableField2
+ * java/lang/invoke/TestStableFloat$NestedStableField2$A
+ * java/lang/invoke/TestStableFloat$NestedStableField3
+ * java/lang/invoke/TestStableFloat$NestedStableField3$A
+ * java/lang/invoke/TestStableFloat$DefaultValue
+ * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableFloat
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableFloat
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableFloat
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableFloat
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableFloat {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(FloatStable.class);
+ run(StaticFloatStable.class);
+ run(VolatileFloatStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(FloatArrayDim1.class);
+ run(FloatArrayDim2.class);
+ run(FloatArrayDim3.class);
+ run(FloatArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable float v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static float get() { return c.v; }
+ public static void test() throws Exception {
+ float val1 = get();
+ c.v = 1.0F; float val2 = get();
+ assertEquals(val1, 0F);
+ assertEquals(val2, 1.0F);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class FloatStable {
+ public @Stable float v;
+
+ public static final FloatStable c = new FloatStable();
+ public static float get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0F; float val1 = get();
+ c.v = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticFloatStable {
+ public static @Stable float v;
+
+ public static final StaticFloatStable c = new StaticFloatStable();
+ public static float get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0F; float val1 = get();
+ c.v = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileFloatStable {
+ public @Stable volatile float v;
+
+ public static final VolatileFloatStable c = new VolatileFloatStable();
+ public static float get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1.0F; float val1 = get();
+ c.v = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class FloatArrayDim1 {
+ public @Stable float[] v;
+
+ public static final FloatArrayDim1 c = new FloatArrayDim1();
+ public static float get() { return c.v[0]; }
+ public static float get1() { return c.v[10]; }
+ public static float[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new float[1]; c.v[0] = 1.0F; float val1 = get();
+ c.v[0] = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+
+ c.v = new float[1]; c.v[0] = 3.0F; float val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+ }
+
+ {
+ c.v = new float[20]; c.v[10] = 1.0F; float val1 = get1();
+ c.v[10] = 2.0F; float val2 = get1();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+
+ c.v = new float[20]; c.v[10] = 3.0F; float val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+ }
+
+ {
+ c.v = new float[1]; float[] val1 = get2();
+ c.v = new float[1]; float[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class FloatArrayDim2 {
+ public @Stable float[][] v;
+
+ public static final FloatArrayDim2 c = new FloatArrayDim2();
+ public static float get() { return c.v[0][0]; }
+ public static float[] get1() { return c.v[0]; }
+ public static float[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new float[1][1]; c.v[0][0] = 1.0F; float val1 = get();
+ c.v[0][0] = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+
+ c.v = new float[1][1]; c.v[0][0] = 3.0F; float val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+
+ c.v[0] = new float[1]; c.v[0][0] = 4.0F; float val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
+ }
+
+ {
+ c.v = new float[1][1]; float[] val1 = get1();
+ c.v[0] = new float[1]; float[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1]; float[][] val1 = get2();
+ c.v = new float[1][1]; float[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class FloatArrayDim3 {
+ public @Stable float[][][] v;
+
+ public static final FloatArrayDim3 c = new FloatArrayDim3();
+ public static float get() { return c.v[0][0][0]; }
+ public static float[] get1() { return c.v[0][0]; }
+ public static float[][] get2() { return c.v[0]; }
+ public static float[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new float[1][1][1]; c.v[0][0][0] = 1.0F; float val1 = get();
+ c.v[0][0][0] = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+
+ c.v = new float[1][1][1]; c.v[0][0][0] = 3.0F; float val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+
+ c.v[0] = new float[1][1]; c.v[0][0][0] = 4.0F; float val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
+
+ c.v[0][0] = new float[1]; c.v[0][0][0] = 5.0F; float val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F));
+ }
+
+ {
+ c.v = new float[1][1][1]; float[] val1 = get1();
+ c.v[0][0] = new float[1]; float[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1]; float[][] val1 = get2();
+ c.v[0] = new float[1][1]; float[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1]; float[][][] val1 = get3();
+ c.v = new float[1][1][1]; float[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class FloatArrayDim4 {
+ public @Stable float[][][][] v;
+
+ public static final FloatArrayDim4 c = new FloatArrayDim4();
+ public static float get() { return c.v[0][0][0][0]; }
+ public static float[] get1() { return c.v[0][0][0]; }
+ public static float[][] get2() { return c.v[0][0]; }
+ public static float[][][] get3() { return c.v[0]; }
+ public static float[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 1.0F; float val1 = get();
+ c.v[0][0][0][0] = 2.0F; float val2 = get();
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+
+ c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 3.0F; float val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+
+ c.v[0] = new float[1][1][1]; c.v[0][0][0][0] = 4.0F; float val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
+
+ c.v[0][0] = new float[1][1]; c.v[0][0][0][0] = 5.0F; float val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F));
+
+ c.v[0][0][0] = new float[1]; c.v[0][0][0][0] = 6.0F; float val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1.0F : 6.0F));
+ }
+
+ {
+ c.v = new float[1][1][1][1]; float[] val1 = get1();
+ c.v[0][0][0] = new float[1]; float[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1][1]; float[][] val1 = get2();
+ c.v[0][0] = new float[1][1]; float[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1][1]; float[][][] val1 = get3();
+ c.v[0] = new float[1][1][1]; float[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1][1]; float[][][][] val1 = get4();
+ c.v = new float[1][1][1][1]; float[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static float get() { return ((float[])c.v)[0]; }
+ public static float[] get1() { return (float[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new float[1]; ((float[])c.v)[0] = 1.0F; float val1 = get();
+ ((float[])c.v)[0] = 2.0F; float val2 = get();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, 2.0F);
+ }
+
+ {
+ c.v = new float[1]; float[] val1 = get1();
+ c.v = new float[1]; float[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static float get() { return ((float[][])c.v)[0][0]; }
+ public static float[] get1() { return (float[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new float[1][1]; ((float[][])c.v)[0][0] = 1.0F; float val1 = get();
+ ((float[][])c.v)[0][0] = 2.0F; float val2 = get();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, 2.0F);
+ }
+
+ {
+ c.v = new float[1][1]; c.v[0] = new float[0]; float[] val1 = get1();
+ c.v[0] = new float[0]; float[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[0][0]; Object[] val1 = get2();
+ c.v = new float[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static float get() { return ((float[][][])c.v)[0][0][0]; }
+ public static float[] get1() { return (float[])(c.v[0][0]); }
+ public static float[][] get2() { return (float[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new float[1][1][1]; ((float[][][])c.v)[0][0][0] = 1.0F; float val1 = get();
+ ((float[][][])c.v)[0][0][0] = 2.0F; float val2 = get();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, 2.0F);
+ }
+
+ {
+ c.v = new float[1][1][1]; c.v[0][0] = new float[0]; float[] val1 = get1();
+ c.v[0][0] = new float[0]; float[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[1][1][1]; c.v[0] = new float[0][0]; float[][] val1 = get2();
+ c.v[0] = new float[0][0]; float[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new float[0][0][0]; Object[][] val1 = get3();
+ c.v = new float[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable float a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static float get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1.0F; A val1 = get();
+ c.v.a = 2.0F; A val2 = get();
+
+ assertEquals(val1.a, 2.0F);
+ assertEquals(val2.a, 2.0F);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1.0F; float val1 = get1();
+ c.v.a = 2.0F; float val2 = get1();
+ c.v = new A(); c.v.a = 3.0F; float val3 = get1();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable float a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static float get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1.0F; c.v.next.a = 1.0F; A val1 = get();
+ c.v.a = 2.0F; c.v.next.a = 2.0F; A val2 = get();
+
+ assertEquals(val1.a, 2.0F);
+ assertEquals(val2.a, 2.0F);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1.0F; float val1 = get1();
+ c.v.a = 2.0F; float val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3.0F; float val3 = get1();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
+ assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable float a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static float get() { return c.v.left.left.left.a; }
+ public static float get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1.0F; float val1 = get(); float val2 = get1();
+ c.v.a = 2.0F; float val3 = get(); float val4 = get1();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F));
+
+ assertEquals(val2, 1.0F);
+ assertEquals(val4, 2.0F);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable float a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static float get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static float get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1.0F; float val1 = get(); float val2 = get1();
+ elem.a = 2.0F; float val3 = get(); float val4 = get1();
+
+ assertEquals(val1, 1.0F);
+ assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F));
+
+ assertEquals(val2, 1.0F);
+ assertEquals(val4, 2.0F);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(float i, float j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableInt.java b/hotspot/test/compiler/stable/TestStableInt.java
new file mode 100644
index 00000000000..9632a8dc39d
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableInt.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableInt
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableInt.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableInt
+ * java/lang/invoke/TestStableInt$IntStable
+ * java/lang/invoke/TestStableInt$StaticIntStable
+ * java/lang/invoke/TestStableInt$VolatileIntStable
+ * java/lang/invoke/TestStableInt$IntArrayDim1
+ * java/lang/invoke/TestStableInt$IntArrayDim2
+ * java/lang/invoke/TestStableInt$IntArrayDim3
+ * java/lang/invoke/TestStableInt$IntArrayDim4
+ * java/lang/invoke/TestStableInt$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableInt$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableInt$NestedStableField
+ * java/lang/invoke/TestStableInt$NestedStableField$A
+ * java/lang/invoke/TestStableInt$NestedStableField1
+ * java/lang/invoke/TestStableInt$NestedStableField1$A
+ * java/lang/invoke/TestStableInt$NestedStableField2
+ * java/lang/invoke/TestStableInt$NestedStableField2$A
+ * java/lang/invoke/TestStableInt$NestedStableField3
+ * java/lang/invoke/TestStableInt$NestedStableField3$A
+ * java/lang/invoke/TestStableInt$DefaultValue
+ * java/lang/invoke/TestStableInt$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableInt
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableInt
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableInt
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableInt
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableInt {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(IntStable.class);
+ run(StaticIntStable.class);
+ run(VolatileIntStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(IntArrayDim1.class);
+ run(IntArrayDim2.class);
+ run(IntArrayDim3.class);
+ run(IntArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable int v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static int get() { return c.v; }
+ public static void test() throws Exception {
+ int val1 = get();
+ c.v = 1; int val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 1);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class IntStable {
+ public @Stable int v;
+
+ public static final IntStable c = new IntStable();
+ public static int get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; int val1 = get();
+ c.v = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticIntStable {
+ public static @Stable int v;
+
+ public static final StaticIntStable c = new StaticIntStable();
+ public static int get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; int val1 = get();
+ c.v = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileIntStable {
+ public @Stable volatile int v;
+
+ public static final VolatileIntStable c = new VolatileIntStable();
+ public static int get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; int val1 = get();
+ c.v = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class IntArrayDim1 {
+ public @Stable int[] v;
+
+ public static final IntArrayDim1 c = new IntArrayDim1();
+ public static int get() { return c.v[0]; }
+ public static int get1() { return c.v[10]; }
+ public static int[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new int[1]; c.v[0] = 1; int val1 = get();
+ c.v[0] = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new int[1]; c.v[0] = 3; int val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new int[20]; c.v[10] = 1; int val1 = get1();
+ c.v[10] = 2; int val2 = get1();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new int[20]; c.v[10] = 3; int val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new int[1]; int[] val1 = get2();
+ c.v = new int[1]; int[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class IntArrayDim2 {
+ public @Stable int[][] v;
+
+ public static final IntArrayDim2 c = new IntArrayDim2();
+ public static int get() { return c.v[0][0]; }
+ public static int[] get1() { return c.v[0]; }
+ public static int[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new int[1][1]; c.v[0][0] = 1; int val1 = get();
+ c.v[0][0] = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new int[1][1]; c.v[0][0] = 3; int val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new int[1]; c.v[0][0] = 4; int val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+ }
+
+ {
+ c.v = new int[1][1]; int[] val1 = get1();
+ c.v[0] = new int[1]; int[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1]; int[][] val1 = get2();
+ c.v = new int[1][1]; int[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class IntArrayDim3 {
+ public @Stable int[][][] v;
+
+ public static final IntArrayDim3 c = new IntArrayDim3();
+ public static int get() { return c.v[0][0][0]; }
+ public static int[] get1() { return c.v[0][0]; }
+ public static int[][] get2() { return c.v[0]; }
+ public static int[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new int[1][1][1]; c.v[0][0][0] = 1; int val1 = get();
+ c.v[0][0][0] = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new int[1][1][1]; c.v[0][0][0] = 3; int val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new int[1][1]; c.v[0][0][0] = 4; int val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new int[1]; c.v[0][0][0] = 5; int val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+ }
+
+ {
+ c.v = new int[1][1][1]; int[] val1 = get1();
+ c.v[0][0] = new int[1]; int[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1]; int[][] val1 = get2();
+ c.v[0] = new int[1][1]; int[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1]; int[][][] val1 = get3();
+ c.v = new int[1][1][1]; int[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class IntArrayDim4 {
+ public @Stable int[][][][] v;
+
+ public static final IntArrayDim4 c = new IntArrayDim4();
+ public static int get() { return c.v[0][0][0][0]; }
+ public static int[] get1() { return c.v[0][0][0]; }
+ public static int[][] get2() { return c.v[0][0]; }
+ public static int[][][] get3() { return c.v[0]; }
+ public static int[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 1; int val1 = get();
+ c.v[0][0][0][0] = 2; int val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 3; int val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new int[1][1][1]; c.v[0][0][0][0] = 4; int val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new int[1][1]; c.v[0][0][0][0] = 5; int val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+
+ c.v[0][0][0] = new int[1]; c.v[0][0][0][0] = 6; int val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1 : 6));
+ }
+
+ {
+ c.v = new int[1][1][1][1]; int[] val1 = get1();
+ c.v[0][0][0] = new int[1]; int[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1][1]; int[][] val1 = get2();
+ c.v[0][0] = new int[1][1]; int[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1][1]; int[][][] val1 = get3();
+ c.v[0] = new int[1][1][1]; int[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1][1]; int[][][][] val1 = get4();
+ c.v = new int[1][1][1][1]; int[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static int get() { return ((int[])c.v)[0]; }
+ public static int[] get1() { return (int[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new int[1]; ((int[])c.v)[0] = 1; int val1 = get();
+ ((int[])c.v)[0] = 2; int val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new int[1]; int[] val1 = get1();
+ c.v = new int[1]; int[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static int get() { return ((int[][])c.v)[0][0]; }
+ public static int[] get1() { return (int[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new int[1][1]; ((int[][])c.v)[0][0] = 1; int val1 = get();
+ ((int[][])c.v)[0][0] = 2; int val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new int[1][1]; c.v[0] = new int[0]; int[] val1 = get1();
+ c.v[0] = new int[0]; int[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[0][0]; Object[] val1 = get2();
+ c.v = new int[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static int get() { return ((int[][][])c.v)[0][0][0]; }
+ public static int[] get1() { return (int[])(c.v[0][0]); }
+ public static int[][] get2() { return (int[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new int[1][1][1]; ((int[][][])c.v)[0][0][0] = 1; int val1 = get();
+ ((int[][][])c.v)[0][0][0] = 2; int val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new int[1][1][1]; c.v[0][0] = new int[0]; int[] val1 = get1();
+ c.v[0][0] = new int[0]; int[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[1][1][1]; c.v[0] = new int[0][0]; int[][] val1 = get2();
+ c.v[0] = new int[0][0]; int[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new int[0][0][0]; Object[][] val1 = get3();
+ c.v = new int[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable int a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static int get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1; A val1 = get();
+ c.v.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1; int val1 = get1();
+ c.v.a = 2; int val2 = get1();
+ c.v = new A(); c.v.a = 3; int val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable int a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static int get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1; c.v.next.a = 1; A val1 = get();
+ c.v.a = 2; c.v.next.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1; int val1 = get1();
+ c.v.a = 2; int val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3; int val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable int a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static int get() { return c.v.left.left.left.a; }
+ public static int get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1; int val1 = get(); int val2 = get1();
+ c.v.a = 2; int val3 = get(); int val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable int a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static int get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static int get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1; int val1 = get(); int val2 = get1();
+ elem.a = 2; int val3 = get(); int val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableLong.java b/hotspot/test/compiler/stable/TestStableLong.java
new file mode 100644
index 00000000000..d1c72f5609c
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableLong.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableLong
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableLong.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableLong
+ * java/lang/invoke/TestStableLong$LongStable
+ * java/lang/invoke/TestStableLong$StaticLongStable
+ * java/lang/invoke/TestStableLong$VolatileLongStable
+ * java/lang/invoke/TestStableLong$LongArrayDim1
+ * java/lang/invoke/TestStableLong$LongArrayDim2
+ * java/lang/invoke/TestStableLong$LongArrayDim3
+ * java/lang/invoke/TestStableLong$LongArrayDim4
+ * java/lang/invoke/TestStableLong$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableLong$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableLong$NestedStableField
+ * java/lang/invoke/TestStableLong$NestedStableField$A
+ * java/lang/invoke/TestStableLong$NestedStableField1
+ * java/lang/invoke/TestStableLong$NestedStableField1$A
+ * java/lang/invoke/TestStableLong$NestedStableField2
+ * java/lang/invoke/TestStableLong$NestedStableField2$A
+ * java/lang/invoke/TestStableLong$NestedStableField3
+ * java/lang/invoke/TestStableLong$NestedStableField3$A
+ * java/lang/invoke/TestStableLong$DefaultValue
+ * java/lang/invoke/TestStableLong$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableLong
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableLong
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableLong
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableLong
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableLong {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(LongStable.class);
+ run(StaticLongStable.class);
+ run(VolatileLongStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(LongArrayDim1.class);
+ run(LongArrayDim2.class);
+ run(LongArrayDim3.class);
+ run(LongArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable long v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static long get() { return c.v; }
+ public static void test() throws Exception {
+ long val1 = get();
+ c.v = 1L; long val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 1L);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class LongStable {
+ public @Stable long v;
+
+ public static final LongStable c = new LongStable();
+ public static long get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; long val1 = get();
+ c.v = Long.MAX_VALUE; long val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticLongStable {
+ public static @Stable long v;
+
+ public static final StaticLongStable c = new StaticLongStable();
+ public static long get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; long val1 = get();
+ c.v = Long.MAX_VALUE; long val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileLongStable {
+ public @Stable volatile long v;
+
+ public static final VolatileLongStable c = new VolatileLongStable();
+ public static long get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 5; long val1 = get();
+ c.v = Long.MAX_VALUE; long val2 = get();
+ assertEquals(val1, 5);
+ assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class LongArrayDim1 {
+ public @Stable long[] v;
+
+ public static final LongArrayDim1 c = new LongArrayDim1();
+ public static long get() { return c.v[0]; }
+ public static long get1() { return c.v[10]; }
+ public static long[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new long[1]; c.v[0] = 1; long val1 = get();
+ c.v[0] = 2; long val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new long[1]; c.v[0] = 3; long val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new long[20]; c.v[10] = 1; long val1 = get1();
+ c.v[10] = 2; long val2 = get1();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new long[20]; c.v[10] = 3; long val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new long[1]; long[] val1 = get2();
+ c.v = new long[1]; long[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class LongArrayDim2 {
+ public @Stable long[][] v;
+
+ public static final LongArrayDim2 c = new LongArrayDim2();
+ public static long get() { return c.v[0][0]; }
+ public static long[] get1() { return c.v[0]; }
+ public static long[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new long[1][1]; c.v[0][0] = 1; long val1 = get();
+ c.v[0][0] = 2; long val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new long[1][1]; c.v[0][0] = 3; long val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new long[1]; c.v[0][0] = 4; long val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+ }
+
+ {
+ c.v = new long[1][1]; long[] val1 = get1();
+ c.v[0] = new long[1]; long[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1]; long[][] val1 = get2();
+ c.v = new long[1][1]; long[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class LongArrayDim3 {
+ public @Stable long[][][] v;
+
+ public static final LongArrayDim3 c = new LongArrayDim3();
+ public static long get() { return c.v[0][0][0]; }
+ public static long[] get1() { return c.v[0][0]; }
+ public static long[][] get2() { return c.v[0]; }
+ public static long[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new long[1][1][1]; c.v[0][0][0] = 1; long val1 = get();
+ c.v[0][0][0] = 2; long val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new long[1][1][1]; c.v[0][0][0] = 3; long val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new long[1][1]; c.v[0][0][0] = 4; long val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new long[1]; c.v[0][0][0] = 5; long val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+ }
+
+ {
+ c.v = new long[1][1][1]; long[] val1 = get1();
+ c.v[0][0] = new long[1]; long[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1]; long[][] val1 = get2();
+ c.v[0] = new long[1][1]; long[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1]; long[][][] val1 = get3();
+ c.v = new long[1][1][1]; long[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class LongArrayDim4 {
+ public @Stable long[][][][] v;
+
+ public static final LongArrayDim4 c = new LongArrayDim4();
+ public static long get() { return c.v[0][0][0][0]; }
+ public static long[] get1() { return c.v[0][0][0]; }
+ public static long[][] get2() { return c.v[0][0]; }
+ public static long[][][] get3() { return c.v[0]; }
+ public static long[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 1; long val1 = get();
+ c.v[0][0][0][0] = 2; long val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 3; long val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new long[1][1][1]; c.v[0][0][0][0] = 4; long val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new long[1][1]; c.v[0][0][0][0] = 5; long val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+
+ c.v[0][0][0] = new long[1]; c.v[0][0][0][0] = 6; long val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1 : 6));
+ }
+
+ {
+ c.v = new long[1][1][1][1]; long[] val1 = get1();
+ c.v[0][0][0] = new long[1]; long[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1][1]; long[][] val1 = get2();
+ c.v[0][0] = new long[1][1]; long[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1][1]; long[][][] val1 = get3();
+ c.v[0] = new long[1][1][1]; long[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1][1]; long[][][][] val1 = get4();
+ c.v = new long[1][1][1][1]; long[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static long get() { return ((long[])c.v)[0]; }
+ public static long[] get1() { return (long[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new long[1]; ((long[])c.v)[0] = 1; long val1 = get();
+ ((long[])c.v)[0] = 2; long val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new long[1]; long[] val1 = get1();
+ c.v = new long[1]; long[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static long get() { return ((long[][])c.v)[0][0]; }
+ public static long[] get1() { return (long[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new long[1][1]; ((long[][])c.v)[0][0] = 1; long val1 = get();
+ ((long[][])c.v)[0][0] = 2; long val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new long[1][1]; c.v[0] = new long[0]; long[] val1 = get1();
+ c.v[0] = new long[0]; long[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[0][0]; Object[] val1 = get2();
+ c.v = new long[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static long get() { return ((long[][][])c.v)[0][0][0]; }
+ public static long[] get1() { return (long[])(c.v[0][0]); }
+ public static long[][] get2() { return (long[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new long[1][1][1]; ((long[][][])c.v)[0][0][0] = 1L; long val1 = get();
+ ((long[][][])c.v)[0][0][0] = 2L; long val2 = get();
+
+ assertEquals(val1, 1L);
+ assertEquals(val2, 2L);
+ }
+
+ {
+ c.v = new long[1][1][1]; c.v[0][0] = new long[0]; long[] val1 = get1();
+ c.v[0][0] = new long[0]; long[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[1][1][1]; c.v[0] = new long[0][0]; long[][] val1 = get2();
+ c.v[0] = new long[0][0]; long[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new long[0][0][0]; Object[][] val1 = get3();
+ c.v = new long[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable long a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static long get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1; A val1 = get();
+ c.v.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1; long val1 = get1();
+ c.v.a = 2; long val2 = get1();
+ c.v = new A(); c.v.a = 3; long val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable long a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static long get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1; c.v.next.a = 1; A val1 = get();
+ c.v.a = 2; c.v.next.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1; long val1 = get1();
+ c.v.a = 2; long val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3; long val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable long a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static long get() { return c.v.left.left.left.a; }
+ public static long get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1; long val1 = get(); long val2 = get1();
+ c.v.a = 2; long val3 = get(); long val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable long a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static long get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static long get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1; long val1 = get(); long val2 = get1();
+ elem.a = 2; long val3 = get(); long val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(long i, long j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableObject.java b/hotspot/test/compiler/stable/TestStableObject.java
new file mode 100644
index 00000000000..7958c6500c4
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableObject.java
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableObject
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableObject.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableObject
+ * java/lang/invoke/TestStableObject$ObjectStable
+ * java/lang/invoke/TestStableObject$StaticObjectStable
+ * java/lang/invoke/TestStableObject$VolatileObjectStable
+ * java/lang/invoke/TestStableObject$ObjectArrayDim1
+ * java/lang/invoke/TestStableObject$ObjectArrayDim2
+ * java/lang/invoke/TestStableObject$ObjectArrayDim3
+ * java/lang/invoke/TestStableObject$ObjectArrayDim4
+ * java/lang/invoke/TestStableObject$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableObject$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableObject$NestedStableField
+ * java/lang/invoke/TestStableObject$NestedStableField$A
+ * java/lang/invoke/TestStableObject$NestedStableField1
+ * java/lang/invoke/TestStableObject$NestedStableField1$A
+ * java/lang/invoke/TestStableObject$NestedStableField2
+ * java/lang/invoke/TestStableObject$NestedStableField2$A
+ * java/lang/invoke/TestStableObject$NestedStableField3
+ * java/lang/invoke/TestStableObject$NestedStableField3$A
+ * java/lang/invoke/TestStableObject$Values
+ * java/lang/invoke/TestStableObject$DefaultValue
+ * java/lang/invoke/TestStableObject$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableObject
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableObject
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableObject
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableObject
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableObject {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(ObjectStable.class);
+ run(StaticObjectStable.class);
+ run(VolatileObjectStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(ObjectArrayDim1.class);
+ run(ObjectArrayDim2.class);
+ run(ObjectArrayDim3.class);
+ run(ObjectArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ enum Values {A, B, C, D, E, F}
+
+ static class DefaultValue {
+ public @Stable Object v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static Object get() { return c.v; }
+ public static void test() throws Exception {
+ Object val1 = get();
+ c.v = Values.A; Object val2 = get();
+ assertEquals(val1, null);
+ assertEquals(val2, Values.A);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectStable {
+ public @Stable Values v;
+
+ public static final ObjectStable c = new ObjectStable ();
+ public static Values get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = Values.A; Values val1 = get();
+ c.v = Values.B; Values val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticObjectStable {
+ public static @Stable Values v;
+
+ public static final ObjectStable c = new ObjectStable ();
+ public static Values get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = Values.A; Values val1 = get();
+ c.v = Values.B; Values val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileObjectStable {
+ public @Stable volatile Values v;
+
+ public static final VolatileObjectStable c = new VolatileObjectStable ();
+ public static Values get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = Values.A; Values val1 = get();
+ c.v = Values.B; Values val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class ObjectArrayDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayDim1 c = new ObjectArrayDim1();
+ public static Object get() { return c.v[0]; }
+ public static Object get1() { return c.v[10]; }
+ public static Object[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1]; c.v[0] = Values.A; Object val1 = get();
+ c.v[0] = Values.B; Object val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+
+ c.v = new Object[1]; c.v[0] = Values.C; Object val3 = get();
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+ }
+
+ {
+ c.v = new Object[20]; c.v[10] = Values.A; Object val1 = get1();
+ c.v[10] = Values.B; Object val2 = get1();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+
+ c.v = new Object[20]; c.v[10] = Values.C; Object val3 = get1();
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+ }
+
+ {
+ c.v = new Object[1]; Object[] val1 = get2();
+ c.v = new Object[1]; Object[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayDim2 c = new ObjectArrayDim2();
+ public static Object get() { return c.v[0][0]; }
+ public static Object[] get1() { return c.v[0]; }
+ public static Object[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1][1]; c.v[0][0] = Values.A; Object val1 = get();
+ c.v[0][0] = Values.B; Object val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+
+ c.v = new Object[1][1]; c.v[0][0] = Values.C; Object val3 = get();
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+
+ c.v[0] = new Object[1]; c.v[0][0] = Values.D; Object val4 = get();
+ assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
+ }
+
+ {
+ c.v = new Object[1][1]; Object[] val1 = get1();
+ c.v[0] = new Object[1]; Object[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1]; Object[][] val1 = get2();
+ c.v = new Object[1][1]; Object[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayDim3 {
+ public @Stable Object[][][] v;
+
+ public static final ObjectArrayDim3 c = new ObjectArrayDim3();
+ public static Object get() { return c.v[0][0][0]; }
+ public static Object[] get1() { return c.v[0][0]; }
+ public static Object[][] get2() { return c.v[0]; }
+ public static Object[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1][1][1]; c.v[0][0][0] = Values.A; Object val1 = get();
+ c.v[0][0][0] = Values.B; Object val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+
+ c.v = new Object[1][1][1]; c.v[0][0][0] = Values.C; Object val3 = get();
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+
+ c.v[0] = new Object[1][1]; c.v[0][0][0] = Values.D; Object val4 = get();
+ assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
+
+ c.v[0][0] = new Object[1]; c.v[0][0][0] = Values.E; Object val5 = get();
+ assertEquals(val5, (isStableEnabled ? Values.A : Values.E));
+ }
+
+ {
+ c.v = new Object[1][1][1]; Object[] val1 = get1();
+ c.v[0][0] = new Object[1]; Object[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1]; Object[][] val1 = get2();
+ c.v[0] = new Object[1][1]; Object[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1]; Object[][][] val1 = get3();
+ c.v = new Object[1][1][1]; Object[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayDim4 {
+ public @Stable Object[][][][] v;
+
+ public static final ObjectArrayDim4 c = new ObjectArrayDim4();
+ public static Object get() { return c.v[0][0][0][0]; }
+ public static Object[] get1() { return c.v[0][0][0]; }
+ public static Object[][] get2() { return c.v[0][0]; }
+ public static Object[][][] get3() { return c.v[0]; }
+ public static Object[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.A; Object val1 = get();
+ c.v[0][0][0][0] = Values.B; Object val2 = get();
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+
+ c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.C; Object val3 = get();
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+
+ c.v[0] = new Object[1][1][1]; c.v[0][0][0][0] = Values.D; Object val4 = get();
+ assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
+
+ c.v[0][0] = new Object[1][1]; c.v[0][0][0][0] = Values.E; Object val5 = get();
+ assertEquals(val5, (isStableEnabled ? Values.A : Values.E));
+
+ c.v[0][0][0] = new Object[1]; c.v[0][0][0][0] = Values.F; Object val6 = get();
+ assertEquals(val6, (isStableEnabled ? Values.A : Values.F));
+ }
+
+ {
+ c.v = new Object[1][1][1][1]; Object[] val1 = get1();
+ c.v[0][0][0] = new Object[1]; Object[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1][1]; Object[][] val1 = get2();
+ c.v[0][0] = new Object[1][1]; Object[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1][1]; Object[][][] val1 = get3();
+ c.v[0] = new Object[1][1][1]; Object[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1][1]; Object[][][][] val1 = get4();
+ c.v = new Object[1][1][1][1]; Object[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static Object get() { return ((Object[])c.v)[0]; }
+ public static Object[] get1() { return (Object[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1]; ((Object[])c.v)[0] = Values.A; Object val1 = get();
+ ((Object[])c.v)[0] = Values.B; Object val2 = get();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val2, Values.B);
+ }
+
+ {
+ c.v = new Object[1]; Object[] val1 = get1();
+ c.v = new Object[1]; Object[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static Object get() { return ((Object[][])c.v)[0][0]; }
+ public static Object[] get1() { return (Object[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1][1]; ((Object[][])c.v)[0][0] = Values.A; Object val1 = get();
+ ((Object[][])c.v)[0][0] = Values.B; Object val2 = get();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val2, Values.B);
+ }
+
+ {
+ c.v = new Object[1][1]; c.v[0] = new Object[0]; Object[] val1 = get1();
+ c.v[0] = new Object[0]; Object[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[0][0]; Object[] val1 = get2();
+ c.v = new Object[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static Object get() { return ((Object[][][])c.v)[0][0][0]; }
+ public static Object[] get1() { return (Object[])(c.v[0][0]); }
+ public static Object[][] get2() { return (Object[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new Object[1][1][1]; ((Object[][][])c.v)[0][0][0] = Values.A; Object val1 = get();
+ ((Object[][][])c.v)[0][0][0] = Values.B; Object val2 = get();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val2, Values.B);
+ }
+
+ {
+ c.v = new Object[1][1][1]; c.v[0][0] = new Object[0]; Object[] val1 = get1();
+ c.v[0][0] = new Object[0]; Object[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[1][1][1]; c.v[0] = new Object[0][0]; Object[][] val1 = get2();
+ c.v[0] = new Object[0][0]; Object[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new Object[0][0][0]; Object[][] val1 = get3();
+ c.v = new Object[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable Object a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static Object get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = Values.A; A val1 = get();
+ c.v.a = Values.B; A val2 = get();
+
+ assertEquals(val1.a, Values.B);
+ assertEquals(val2.a, Values.B);
+ }
+
+ {
+ c.v = new A(); c.v.a = Values.A; Object val1 = get1();
+ c.v.a = Values.B; Object val2 = get1();
+ c.v = new A(); c.v.a = Values.C; Object val3 = get1();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable Object a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static Object get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = Values.A; c.v.next.a = Values.A; A val1 = get();
+ c.v.a = Values.B; c.v.next.a = Values.B; A val2 = get();
+
+ assertEquals(val1.a, Values.B);
+ assertEquals(val2.a, Values.B);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = Values.A; Object val1 = get1();
+ c.v.a = Values.B; Object val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = Values.C; Object val3 = get1();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable Object a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static Object get() { return c.v.left.left.left.a; }
+ public static Object get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = Values.A; Object val1 = get(); Object val2 = get1();
+ c.v.a = Values.B; Object val3 = get(); Object val4 = get1();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.B));
+
+ assertEquals(val2, Values.A);
+ assertEquals(val4, Values.B);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable Object a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static Object get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static Object get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = Values.A; Object val1 = get(); Object val2 = get1();
+ elem.a = Values.B; Object val3 = get(); Object val4 = get1();
+
+ assertEquals(val1, Values.A);
+ assertEquals(val3, (isStableEnabled ? Values.A : Values.B));
+
+ assertEquals(val2, Values.A);
+ assertEquals(val4, Values.B);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(Object i, Object j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
diff --git a/hotspot/test/compiler/stable/TestStableShort.java b/hotspot/test/compiler/stable/TestStableShort.java
new file mode 100644
index 00000000000..a80d0726db6
--- /dev/null
+++ b/hotspot/test/compiler/stable/TestStableShort.java
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/*
+ * @test TestStableShort
+ * @summary tests on stable fields and arrays
+ * @library /testlibrary
+ * @compile -XDignore.symbol.file TestStableShort.java
+ * @run main ClassFileInstaller
+ * java/lang/invoke/TestStableShort
+ * java/lang/invoke/TestStableShort$ShortStable
+ * java/lang/invoke/TestStableShort$StaticShortStable
+ * java/lang/invoke/TestStableShort$VolatileShortStable
+ * java/lang/invoke/TestStableShort$ShortArrayDim1
+ * java/lang/invoke/TestStableShort$ShortArrayDim2
+ * java/lang/invoke/TestStableShort$ShortArrayDim3
+ * java/lang/invoke/TestStableShort$ShortArrayDim4
+ * java/lang/invoke/TestStableShort$ObjectArrayLowerDim0
+ * java/lang/invoke/TestStableShort$ObjectArrayLowerDim1
+ * java/lang/invoke/TestStableShort$NestedStableField
+ * java/lang/invoke/TestStableShort$NestedStableField$A
+ * java/lang/invoke/TestStableShort$NestedStableField1
+ * java/lang/invoke/TestStableShort$NestedStableField1$A
+ * java/lang/invoke/TestStableShort$NestedStableField2
+ * java/lang/invoke/TestStableShort$NestedStableField2$A
+ * java/lang/invoke/TestStableShort$NestedStableField3
+ * java/lang/invoke/TestStableShort$NestedStableField3$A
+ * java/lang/invoke/TestStableShort$DefaultValue
+ * java/lang/invoke/TestStableShort$ObjectArrayLowerDim2
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableShort
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableShort
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableShort
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
+ * -server -XX:-TieredCompilation -Xcomp
+ * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
+ * java.lang.invoke.TestStableShort
+ */
+package java.lang.invoke;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import com.sun.management.VMOption;
+import sun.management.ManagementFactoryHelper;
+import java.lang.reflect.InvocationTargetException;
+
+public class TestStableShort {
+ public static void main(String[] args) throws Exception {
+ System.out.println("@Stable enabled: "+isStableEnabled);
+ System.out.println();
+
+ run(DefaultValue.class);
+ run(ShortStable.class);
+ run(StaticShortStable.class);
+ run(VolatileShortStable.class);
+
+ // @Stable arrays: Dim 1-4
+ run(ShortArrayDim1.class);
+ run(ShortArrayDim2.class);
+ run(ShortArrayDim3.class);
+ run(ShortArrayDim4.class);
+
+ // @Stable Object field: dynamic arrays
+ run(ObjectArrayLowerDim0.class);
+ run(ObjectArrayLowerDim1.class);
+ run(ObjectArrayLowerDim2.class);
+
+ // Nested @Stable fields
+ run(NestedStableField.class);
+ run(NestedStableField1.class);
+ run(NestedStableField2.class);
+ run(NestedStableField3.class);
+
+ if (failed) {
+ throw new Error("TEST FAILED");
+ }
+ }
+
+ /* ==================================================== */
+
+ static class DefaultValue {
+ public @Stable short v;
+
+ public static final DefaultValue c = new DefaultValue();
+ public static short get() { return c.v; }
+ public static void test() throws Exception {
+ short val1 = get();
+ c.v = 1; short val2 = get();
+ assertEquals(val1, 0);
+ assertEquals(val2, 1);
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ShortStable {
+ public @Stable short v;
+
+ public static final ShortStable c = new ShortStable();
+ public static short get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; short val1 = get();
+ c.v = 32767; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 32767));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class StaticShortStable {
+ public static @Stable short v;
+
+ public static final StaticShortStable c = new StaticShortStable();
+ public static short get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; short val1 = get();
+ c.v = 32767; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 32767));
+ }
+ }
+
+ /* ==================================================== */
+
+ static class VolatileShortStable {
+ public @Stable volatile short v;
+
+ public static final VolatileShortStable c = new VolatileShortStable();
+ public static short get() { return c.v; }
+ public static void test() throws Exception {
+ c.v = 1; short val1 = get();
+ c.v = 32767; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 32767));
+ }
+ }
+
+ /* ==================================================== */
+ // @Stable array == field && all components are stable
+
+ static class ShortArrayDim1 {
+ public @Stable short[] v;
+
+ public static final ShortArrayDim1 c = new ShortArrayDim1();
+ public static short get() { return c.v[0]; }
+ public static short get1() { return c.v[10]; }
+ public static short[] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new short[1]; c.v[0] = 1; short val1 = get();
+ c.v[0] = 2; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new short[1]; c.v[0] = 3; short val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new short[20]; c.v[10] = 1; short val1 = get1();
+ c.v[10] = 2; short val2 = get1();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new short[20]; c.v[10] = 3; short val3 = get1();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+
+ {
+ c.v = new short[1]; short[] val1 = get2();
+ c.v = new short[1]; short[] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ShortArrayDim2 {
+ public @Stable short[][] v;
+
+ public static final ShortArrayDim2 c = new ShortArrayDim2();
+ public static short get() { return c.v[0][0]; }
+ public static short[] get1() { return c.v[0]; }
+ public static short[][] get2() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new short[1][1]; c.v[0][0] = 1; short val1 = get();
+ c.v[0][0] = 2; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new short[1][1]; c.v[0][0] = 3; short val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new short[1]; c.v[0][0] = 4; short val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+ }
+
+ {
+ c.v = new short[1][1]; short[] val1 = get1();
+ c.v[0] = new short[1]; short[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1]; short[][] val1 = get2();
+ c.v = new short[1][1]; short[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ShortArrayDim3 {
+ public @Stable short[][][] v;
+
+ public static final ShortArrayDim3 c = new ShortArrayDim3();
+ public static short get() { return c.v[0][0][0]; }
+ public static short[] get1() { return c.v[0][0]; }
+ public static short[][] get2() { return c.v[0]; }
+ public static short[][][] get3() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new short[1][1][1]; c.v[0][0][0] = 1; short val1 = get();
+ c.v[0][0][0] = 2; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new short[1][1][1]; c.v[0][0][0] = 3; short val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new short[1][1]; c.v[0][0][0] = 4; short val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new short[1]; c.v[0][0][0] = 5; short val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+ }
+
+ {
+ c.v = new short[1][1][1]; short[] val1 = get1();
+ c.v[0][0] = new short[1]; short[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1]; short[][] val1 = get2();
+ c.v[0] = new short[1][1]; short[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1]; short[][][] val1 = get3();
+ c.v = new short[1][1][1]; short[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ShortArrayDim4 {
+ public @Stable short[][][][] v;
+
+ public static final ShortArrayDim4 c = new ShortArrayDim4();
+ public static short get() { return c.v[0][0][0][0]; }
+ public static short[] get1() { return c.v[0][0][0]; }
+ public static short[][] get2() { return c.v[0][0]; }
+ public static short[][][] get3() { return c.v[0]; }
+ public static short[][][][] get4() { return c.v; }
+ public static void test() throws Exception {
+ {
+ c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 1; short val1 = get();
+ c.v[0][0][0][0] = 2; short val2 = get();
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+
+ c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 3; short val3 = get();
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+
+ c.v[0] = new short[1][1][1]; c.v[0][0][0][0] = 4; short val4 = get();
+ assertEquals(val4, (isStableEnabled ? 1 : 4));
+
+ c.v[0][0] = new short[1][1]; c.v[0][0][0][0] = 5; short val5 = get();
+ assertEquals(val5, (isStableEnabled ? 1 : 5));
+
+ c.v[0][0][0] = new short[1]; c.v[0][0][0][0] = 6; short val6 = get();
+ assertEquals(val6, (isStableEnabled ? 1 : 6));
+ }
+
+ {
+ c.v = new short[1][1][1][1]; short[] val1 = get1();
+ c.v[0][0][0] = new short[1]; short[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1][1]; short[][] val1 = get2();
+ c.v[0][0] = new short[1][1]; short[][] val2 = get2();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1][1]; short[][][] val1 = get3();
+ c.v[0] = new short[1][1][1]; short[][][] val2 = get3();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1][1]; short[][][][] val1 = get4();
+ c.v = new short[1][1][1][1]; short[][][][] val2 = get4();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ }
+ }
+
+ /* ==================================================== */
+ // Dynamic Dim is higher than static
+
+ static class ObjectArrayLowerDim0 {
+ public @Stable Object v;
+
+ public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
+ public static short get() { return ((short[])c.v)[0]; }
+ public static short[] get1() { return (short[])c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new short[1]; ((short[])c.v)[0] = 1; short val1 = get();
+ ((short[])c.v)[0] = 2; short val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new short[1]; short[] val1 = get1();
+ c.v = new short[1]; short[] val2 = get1();
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim1 {
+ public @Stable Object[] v;
+
+ public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
+ public static short get() { return ((short[][])c.v)[0][0]; }
+ public static short[] get1() { return (short[])(c.v[0]); }
+ public static Object[] get2() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new short[1][1]; ((short[][])c.v)[0][0] = 1; short val1 = get();
+ ((short[][])c.v)[0][0] = 2; short val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new short[1][1]; c.v[0] = new short[0]; short[] val1 = get1();
+ c.v[0] = new short[0]; short[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[0][0]; Object[] val1 = get2();
+ c.v = new short[0][0]; Object[] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class ObjectArrayLowerDim2 {
+ public @Stable Object[][] v;
+
+ public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
+ public static short get() { return ((short[][][])c.v)[0][0][0]; }
+ public static short[] get1() { return (short[])(c.v[0][0]); }
+ public static short[][] get2() { return (short[][])(c.v[0]); }
+ public static Object[][] get3() { return c.v; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new short[1][1][1]; ((short[][][])c.v)[0][0][0] = 1; short val1 = get();
+ ((short[][][])c.v)[0][0][0] = 2; short val2 = get();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, 2);
+ }
+
+ {
+ c.v = new short[1][1][1]; c.v[0][0] = new short[0]; short[] val1 = get1();
+ c.v[0][0] = new short[0]; short[] val2 = get1();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[1][1][1]; c.v[0] = new short[0][0]; short[][] val1 = get2();
+ c.v[0] = new short[0][0]; short[][] val2 = get2();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+
+ {
+ c.v = new short[0][0][0]; Object[][] val1 = get3();
+ c.v = new short[0][0][0]; Object[][] val2 = get3();
+
+ assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField {
+ static class A {
+ public @Stable short a;
+
+ }
+ public @Stable A v;
+
+ public static final NestedStableField c = new NestedStableField();
+ public static A get() { return c.v; }
+ public static short get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.a = 1; A val1 = get();
+ c.v.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.a = 1; short val1 = get1();
+ c.v.a = 2; short val2 = get1();
+ c.v = new A(); c.v.a = 3; short val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField1 {
+ static class A {
+ public @Stable short a;
+ public @Stable A next;
+ }
+ public @Stable A v;
+
+ public static final NestedStableField1 c = new NestedStableField1();
+ public static A get() { return c.v.next.next.next.next.next.next.next; }
+ public static short get1() { return get().a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
+ c.v.a = 1; c.v.next.a = 1; A val1 = get();
+ c.v.a = 2; c.v.next.a = 2; A val2 = get();
+
+ assertEquals(val1.a, 2);
+ assertEquals(val2.a, 2);
+ }
+
+ {
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 1; short val1 = get1();
+ c.v.a = 2; short val2 = get1();
+ c.v = new A(); c.v.next = c.v;
+ c.v.a = 3; short val3 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val2, (isStableEnabled ? 1 : 2));
+ assertEquals(val3, (isStableEnabled ? 1 : 3));
+ }
+ }
+ }
+ /* ==================================================== */
+
+ static class NestedStableField2 {
+ static class A {
+ public @Stable short a;
+ public @Stable A left;
+ public A right;
+ }
+
+ public @Stable A v;
+
+ public static final NestedStableField2 c = new NestedStableField2();
+ public static short get() { return c.v.left.left.left.a; }
+ public static short get1() { return c.v.left.left.right.left.a; }
+
+ public static void test() throws Exception {
+ {
+ c.v = new A(); c.v.left = c.v.right = c.v;
+ c.v.a = 1; short val1 = get(); short val2 = get1();
+ c.v.a = 2; short val3 = get(); short val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+
+ static class NestedStableField3 {
+ static class A {
+ public @Stable short a;
+ public @Stable A[] left;
+ public A[] right;
+ }
+
+ public @Stable A[] v;
+
+ public static final NestedStableField3 c = new NestedStableField3();
+ public static short get() { return c.v[0].left[1].left[0].left[1].a; }
+ public static short get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
+
+ public static void test() throws Exception {
+ {
+ A elem = new A();
+ c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
+ elem.a = 1; short val1 = get(); short val2 = get1();
+ elem.a = 2; short val3 = get(); short val4 = get1();
+
+ assertEquals(val1, 1);
+ assertEquals(val3, (isStableEnabled ? 1 : 2));
+
+ assertEquals(val2, 1);
+ assertEquals(val4, 2);
+ }
+ }
+ }
+
+ /* ==================================================== */
+ // Auxiliary methods
+ static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
+ static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
+
+ static boolean failed = false;
+
+ public static void run(Class> test) {
+ Throwable ex = null;
+ System.out.print(test.getName()+": ");
+ try {
+ test.getMethod("test").invoke(null);
+ } catch (InvocationTargetException e) {
+ ex = e.getCause();
+ } catch (Throwable e) {
+ ex = e;
+ } finally {
+ if (ex == null) {
+ System.out.println("PASSED");
+ } else {
+ failed = true;
+ System.out.println("FAILED");
+ ex.printStackTrace(System.out);
+ }
+ }
+ }
+
+ static final boolean isStableEnabled;
+ static {
+ HotSpotDiagnosticMXBean diagnostic
+ = ManagementFactoryHelper.getDiagnosticMXBean();
+ VMOption tmp;
+ try {
+ tmp = diagnostic.getVMOption("FoldStableValues");
+ } catch (IllegalArgumentException e) {
+ tmp = null;
+ }
+ isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
+ }
+}
From 1dbe60a4752f8097718af12558a46d265e3cc801 Mon Sep 17 00:00:00 2001
From: Vladimir Ivanov
Date: Tue, 4 Mar 2014 02:23:16 -0800
Subject: [PATCH 021/116] 8025842: Convert warning("Thread holding lock at
safepoint that vm can block on") to fatal(...)
Reviewed-by: iveresov, roland, coleenp
---
hotspot/src/share/vm/runtime/thread.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp
index d0fb67715ae..bd794da4524 100644
--- a/hotspot/src/share/vm/runtime/thread.cpp
+++ b/hotspot/src/share/vm/runtime/thread.cpp
@@ -910,7 +910,7 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) {
cur != VMOperationRequest_lock &&
cur != VMOperationQueue_lock) ||
cur->rank() == Mutex::special) {
- warning("Thread holding lock at safepoint that vm can block on: %s", cur->name());
+ fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name()));
}
}
}
From fc6e8666a115543bd14620c1f6d1a3f56e381a25 Mon Sep 17 00:00:00 2001
From: Vladimir Ivanov
Date: Tue, 4 Mar 2014 02:33:10 -0800
Subject: [PATCH 022/116] 8036100: Default method returns true for a while, and
then returns false
Reviewed-by: kvn, jrose
---
hotspot/src/share/vm/ci/ciMethod.cpp | 5 ++
.../inlining/InlineDefaultMethod1.java | 58 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 hotspot/test/compiler/inlining/InlineDefaultMethod1.java
diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp
index 86f1ed31bef..c927b10a030 100644
--- a/hotspot/src/share/vm/ci/ciMethod.cpp
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp
@@ -724,6 +724,11 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
VM_ENTRY_MARK;
+ // Disable CHA for default methods for now
+ if (root_m->get_Method()->is_default_method()) {
+ return NULL;
+ }
+
methodHandle target;
{
MutexLocker locker(Compile_lock);
diff --git a/hotspot/test/compiler/inlining/InlineDefaultMethod1.java b/hotspot/test/compiler/inlining/InlineDefaultMethod1.java
new file mode 100644
index 00000000000..d0cadb8fe4e
--- /dev/null
+++ b/hotspot/test/compiler/inlining/InlineDefaultMethod1.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8036100
+ * @summary Default method returns true for a while, and then returns false
+ * @run main/othervm -Xcomp -XX:CompileOnly=InlineDefaultMethod1::test
+ * -XX:CompileOnly=I1::m -XX:CompileOnly=I2::m
+ * InlineDefaultMethod1
+ */
+interface I1 {
+ default public int m() { return 0; }
+}
+
+interface I2 extends I1 {
+ default public int m() { return 1; }
+}
+
+abstract class A implements I1 {
+}
+
+class B extends A implements I2 {
+}
+
+public class InlineDefaultMethod1 {
+ public static void test(A obj) {
+ int id = obj.m();
+ if (id != 1) {
+ throw new AssertionError("Called wrong method: 1 != "+id);
+ }
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+ test(new B());
+ System.out.println("TEST PASSED");
+ }
+}
From 7d7f4bf62a84376a63026d4c4636f968293b0280 Mon Sep 17 00:00:00 2001
From: Volker Simonis
Date: Tue, 4 Mar 2014 17:14:00 +0100
Subject: [PATCH 023/116] 8036614: AIX: fix adjust-mflags.sh to build with GNU
Make 4.0 (adapt 8028407 for AIX)
Reviewed-by: kvn
---
hotspot/make/aix/makefiles/adjust-mflags.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hotspot/make/aix/makefiles/adjust-mflags.sh b/hotspot/make/aix/makefiles/adjust-mflags.sh
index df1aa625b77..6c06819fb74 100644
--- a/hotspot/make/aix/makefiles/adjust-mflags.sh
+++ b/hotspot/make/aix/makefiles/adjust-mflags.sh
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 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
@@ -64,7 +64,7 @@ MFLAGS=`
echo "$MFLAGS" \
| sed '
s/^-/ -/
- s/ -\([^ ][^ ]*\)j/ -\1 -j/
+ s/ -\([^ I][^ I]*\)j/ -\1 -j/
s/ -j[0-9][0-9]*/ -j/
s/ -j\([^ ]\)/ -j -\1/
s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
From 694a2d010b62be897afa765a83f694278fb7dbd1 Mon Sep 17 00:00:00 2001
From: Mario Torre
Date: Tue, 4 Mar 2014 18:52:06 -0800
Subject: [PATCH 024/116] 8036619: Shark: add LLVM 3.4 support
Reviewed-by: twisti
---
hotspot/make/linux/makefiles/zeroshark.make | 3 +
hotspot/src/share/vm/shark/llvmHeaders.hpp | 32 +++++++--
hotspot/src/share/vm/shark/sharkCompiler.cpp | 4 ++
hotspot/src/share/vm/shark/sharkCompiler.hpp | 3 +
hotspot/src/share/vm/shark/sharkInliner.cpp | 4 ++
.../src/share/vm/shark/sharkMemoryManager.cpp | 66 ++++++++++++-------
.../src/share/vm/shark/sharkMemoryManager.hpp | 27 +++++---
7 files changed, 101 insertions(+), 38 deletions(-)
diff --git a/hotspot/make/linux/makefiles/zeroshark.make b/hotspot/make/linux/makefiles/zeroshark.make
index 890a0910e7f..3c10770d42a 100644
--- a/hotspot/make/linux/makefiles/zeroshark.make
+++ b/hotspot/make/linux/makefiles/zeroshark.make
@@ -25,6 +25,9 @@
# Setup common to Zero (non-Shark) and Shark versions of VM
+# override this from the main file because some version of llvm do not like -Wundef
+WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wunused-function -Wunused-value
+
# The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized
OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT)
# The copied fdlibm routines in sharedRuntimeTrans.o must not be optimized
diff --git a/hotspot/src/share/vm/shark/llvmHeaders.hpp b/hotspot/src/share/vm/shark/llvmHeaders.hpp
index 1f2c2c79778..05ef7fea1d3 100644
--- a/hotspot/src/share/vm/shark/llvmHeaders.hpp
+++ b/hotspot/src/share/vm/shark/llvmHeaders.hpp
@@ -36,21 +36,43 @@
#endif
#include
+#include
+
+// includes specific to each version
+#if SHARK_LLVM_VERSION <= 31
+#include
+#include
#include
#include
#include
-#include
#include
#include
#include
-#if SHARK_LLVM_VERSION <= 31
-#include
-#else
+#elif SHARK_LLVM_VERSION <= 32
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#else // SHARK_LLVM_VERSION <= 34
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#endif
+
+// common includes
#include
#include
-#include
#include
#include
#include
diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp
index 17fdcfcbbe3..fe62efdecbd 100644
--- a/hotspot/src/share/vm/shark/sharkCompiler.cpp
+++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp
@@ -364,3 +364,7 @@ const char* SharkCompiler::methodname(const char* klass, const char* method) {
*(dst++) = '\0';
return buf;
}
+
+void SharkCompiler::print_timers() {
+ // do nothing
+}
diff --git a/hotspot/src/share/vm/shark/sharkCompiler.hpp b/hotspot/src/share/vm/shark/sharkCompiler.hpp
index 97400298865..1b8681771a0 100644
--- a/hotspot/src/share/vm/shark/sharkCompiler.hpp
+++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp
@@ -56,6 +56,9 @@ class SharkCompiler : public AbstractCompiler {
// Compile a normal (bytecode) method and install it in the VM
void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
+ // Print compilation timers and statistics
+ void print_timers();
+
// Generate a wrapper for a native (JNI) method
nmethod* generate_native_wrapper(MacroAssembler* masm,
methodHandle target,
diff --git a/hotspot/src/share/vm/shark/sharkInliner.cpp b/hotspot/src/share/vm/shark/sharkInliner.cpp
index 76b63a16342..47465848d7d 100644
--- a/hotspot/src/share/vm/shark/sharkInliner.cpp
+++ b/hotspot/src/share/vm/shark/sharkInliner.cpp
@@ -744,6 +744,10 @@ bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) {
}
bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) {
+ if (!Inline) {
+ return false;
+ }
+
if (SharkIntrinsics::is_intrinsic(target)) {
SharkIntrinsics::inline_intrinsic(target, state);
return true;
diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.cpp b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp
index 20cb0e5ebfe..d986ae8868b 100644
--- a/hotspot/src/share/vm/shark/sharkMemoryManager.cpp
+++ b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp
@@ -59,18 +59,6 @@ void SharkMemoryManager::endFunctionBody(const Function* F,
entry->set_code_limit(FunctionEnd);
}
-unsigned char* SharkMemoryManager::startExceptionTable(const Function* F,
- uintptr_t& ActualSize) {
- return mm()->startExceptionTable(F, ActualSize);
-}
-
-void SharkMemoryManager::endExceptionTable(const Function* F,
- unsigned char* TableStart,
- unsigned char* TableEnd,
- unsigned char* FrameRegister) {
- mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
-}
-
void SharkMemoryManager::setMemoryWritable() {
mm()->setMemoryWritable();
}
@@ -79,10 +67,6 @@ void SharkMemoryManager::setMemoryExecutable() {
mm()->setMemoryExecutable();
}
-void SharkMemoryManager::deallocateExceptionTable(void *ptr) {
- mm()->deallocateExceptionTable(ptr);
-}
-
void SharkMemoryManager::deallocateFunctionBody(void *ptr) {
mm()->deallocateFunctionBody(ptr);
}
@@ -96,14 +80,6 @@ void* SharkMemoryManager::getPointerToNamedFunction(const std::string &Name, boo
return mm()->getPointerToNamedFunction(Name, AbortOnFailure);
}
-uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
- return mm()->allocateCodeSection(Size, Alignment, SectionID);
-}
-
-uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
- return mm()->allocateDataSection(Size, Alignment, SectionID);
-}
-
void SharkMemoryManager::setPoisonMemory(bool poison) {
mm()->setPoisonMemory(poison);
}
@@ -112,3 +88,45 @@ unsigned char *SharkMemoryManager::allocateSpace(intptr_t Size,
unsigned int Alignment) {
return mm()->allocateSpace(Size, Alignment);
}
+
+#if SHARK_LLVM_VERSION <= 32
+
+uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
+ return mm()->allocateCodeSection(Size, Alignment, SectionID);
+}
+
+uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
+ return mm()->allocateDataSection(Size, Alignment, SectionID);
+}
+
+void SharkMemoryManager::deallocateExceptionTable(void *ptr) {
+ mm()->deallocateExceptionTable(ptr);
+}
+
+unsigned char* SharkMemoryManager::startExceptionTable(const Function* F,
+ uintptr_t& ActualSize) {
+ return mm()->startExceptionTable(F, ActualSize);
+}
+
+void SharkMemoryManager::endExceptionTable(const Function* F,
+ unsigned char* TableStart,
+ unsigned char* TableEnd,
+ unsigned char* FrameRegister) {
+ mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
+}
+
+#else
+
+uint8_t *SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) {
+ return mm()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
+}
+
+uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
+ return mm()->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
+}
+
+bool SharkMemoryManager::finalizeMemory(std::string *ErrMsg) {
+ return mm()->finalizeMemory(ErrMsg);
+}
+
+#endif
diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.hpp b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp
index fa725a14502..7a5ad7b3e1c 100644
--- a/hotspot/src/share/vm/shark/sharkMemoryManager.hpp
+++ b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp
@@ -69,23 +69,32 @@ class SharkMemoryManager : public llvm::JITMemoryManager {
void endFunctionBody(const llvm::Function* F,
unsigned char* FunctionStart,
unsigned char* FunctionEnd);
- unsigned char* startExceptionTable(const llvm::Function* F,
- uintptr_t& ActualSize);
- void endExceptionTable(const llvm::Function* F,
- unsigned char* TableStart,
- unsigned char* TableEnd,
- unsigned char* FrameRegister);
+
void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true);
- uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
- uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
void setPoisonMemory(bool);
uint8_t* allocateGlobal(uintptr_t, unsigned int);
void setMemoryWritable();
void setMemoryExecutable();
- void deallocateExceptionTable(void *ptr);
void deallocateFunctionBody(void *ptr);
unsigned char *allocateSpace(intptr_t Size,
unsigned int Alignment);
+
+#if SHARK_LLVM_VERSION <= 32
+uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
+uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
+unsigned char* startExceptionTable(const llvm::Function* F,
+ uintptr_t& ActualSize);
+void deallocateExceptionTable(void *ptr);
+void endExceptionTable(const llvm::Function* F,
+ unsigned char* TableStart,
+ unsigned char* TableEnd,
+ unsigned char* FrameRegister);
+#else
+uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName);
+uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName, bool IsReadOnly);
+bool finalizeMemory(std::string *ErrMsg = 0);
+#endif
+
};
#endif // SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP
From 9150b930938f2cff47765cea4fbaaff90b6dd90f Mon Sep 17 00:00:00 2001
From: Albert Noll
Date: Wed, 5 Mar 2014 06:08:19 +0100
Subject: [PATCH 025/116] 8036092: [TESTBUG]
compiler/uncommontrap/TestSpecTrapClassUnloading.java fails with:
Unrecognized VM option 'UseTypeSpeculation'
Add -XX:+IgnoreUnrecognizedVMOptions to @main/othervm to make the test pass on Client VM
Reviewed-by: kvn, roland
---
.../test/compiler/uncommontrap/TestSpecTrapClassUnloading.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
index 11572672afe..e660ad5e56d 100644
--- a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
+++ b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
@@ -25,7 +25,7 @@
* @test
* @bug 8031752
* @summary speculative traps need to be cleaned up at GC
- * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
*
*/
From 38fd717c30dcacf76aed2cca9e4848f81177f86f Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Wed, 5 Mar 2014 09:29:12 +0100
Subject: [PATCH 026/116] 8035841: assert(dp_src->tag() == dp_dst->tag())
failed: should be same tags 1 != 0 at ciMethodData.cpp:90
Concurrent update of traps with construction of ciMethodData
Reviewed-by: kvn, twisti
---
hotspot/src/share/vm/ci/ciMethodData.cpp | 7 +--
hotspot/src/share/vm/oops/methodData.cpp | 68 ++++++++++++------------
hotspot/src/share/vm/oops/methodData.hpp | 12 ++---
3 files changed, 43 insertions(+), 44 deletions(-)
diff --git a/hotspot/src/share/vm/ci/ciMethodData.cpp b/hotspot/src/share/vm/ci/ciMethodData.cpp
index 950e3d6dd21..bc8794063ad 100644
--- a/hotspot/src/share/vm/ci/ciMethodData.cpp
+++ b/hotspot/src/share/vm/ci/ciMethodData.cpp
@@ -87,8 +87,9 @@ void ciMethodData::load_extra_data() {
DataLayout* dp_dst = extra_data_base();
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
assert(dp_src < end_src, "moved past end of extra data");
- assert(dp_src->tag() == dp_dst->tag(), err_msg("should be same tags %d != %d", dp_src->tag(), dp_dst->tag()));
- switch(dp_src->tag()) {
+ // New traps in the MDO can be added as we translate the copy so
+ // look at the entries in the copy.
+ switch(dp_dst->tag()) {
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
@@ -102,7 +103,7 @@ void ciMethodData::load_extra_data() {
// An empty slot or ArgInfoData entry marks the end of the trap data
return;
default:
- fatal(err_msg("bad tag = %d", dp_src->tag()));
+ fatal(err_msg("bad tag = %d", dp_dst->tag()));
}
}
}
diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp
index b226173d832..0e6e0ec0130 100644
--- a/hotspot/src/share/vm/oops/methodData.cpp
+++ b/hotspot/src/share/vm/oops/methodData.cpp
@@ -1071,7 +1071,8 @@ void MethodData::post_initialize(BytecodeStream* stream) {
}
// Initialize the MethodData* corresponding to a given method.
-MethodData::MethodData(methodHandle method, int size, TRAPS) {
+MethodData::MethodData(methodHandle method, int size, TRAPS)
+ : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {
No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC
ResourceMark rm;
// Set the method back-pointer.
@@ -1235,7 +1236,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) {
return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells));
}
-ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp) {
+ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) {
DataLayout* end = extra_data_limit();
for (;; dp = next_extra(dp)) {
@@ -1257,10 +1258,11 @@ ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout
if (m != NULL) {
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
// data->method() may be null in case of a concurrent
- // allocation. Assume it's for the same method and use that
+ // allocation. Maybe it's for the same method. Try to use that
// entry in that case.
if (dp->bci() == bci) {
if (data->method() == NULL) {
+ assert(concurrent, "impossible because no concurrent allocation");
return NULL;
} else if (data->method() == m) {
return data;
@@ -1289,40 +1291,40 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi
// Allocation in the extra data space has to be atomic because not
// all entries have the same size and non atomic concurrent
// allocation would result in a corrupted extra data space.
- while (true) {
- ProfileData* result = bci_to_extra_data_helper(bci, m, dp);
- if (result != NULL) {
+ ProfileData* result = bci_to_extra_data_helper(bci, m, dp, true);
+ if (result != NULL) {
+ return result;
+ }
+
+ if (create_if_missing && dp < end) {
+ MutexLocker ml(&_extra_data_lock);
+ // Check again now that we have the lock. Another thread may
+ // have added extra data entries.
+ ProfileData* result = bci_to_extra_data_helper(bci, m, dp, false);
+ if (result != NULL || dp >= end) {
return result;
}
- if (create_if_missing && dp < end) {
- assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
- assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
- u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
- // SpeculativeTrapData is 2 slots. Make sure we have room.
- if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
- return NULL;
- }
- DataLayout temp;
- temp.initialize(tag, bci, 0);
- // May have been set concurrently
- if (dp->header() != temp.header() && !dp->atomic_set_header(temp.header())) {
- // Allocation failure because of concurrent allocation. Try
- // again.
- continue;
- }
- assert(dp->tag() == tag, "sane");
- assert(dp->bci() == bci, "no concurrent allocation");
- if (tag == DataLayout::bit_data_tag) {
- return new BitData(dp);
- } else {
- // If being allocated concurrently, one trap may be lost
- SpeculativeTrapData* data = new SpeculativeTrapData(dp);
- data->set_method(m);
- return data;
- }
+ assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
+ assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
+ u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
+ // SpeculativeTrapData is 2 slots. Make sure we have room.
+ if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
+ return NULL;
+ }
+ DataLayout temp;
+ temp.initialize(tag, bci, 0);
+
+ dp->set_header(temp.header());
+ assert(dp->tag() == tag, "sane");
+ assert(dp->bci() == bci, "no concurrent allocation");
+ if (tag == DataLayout::bit_data_tag) {
+ return new BitData(dp);
+ } else {
+ SpeculativeTrapData* data = new SpeculativeTrapData(dp);
+ data->set_method(m);
+ return data;
}
- return NULL;
}
return NULL;
}
diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp
index 76b0708f233..e0218f9fd47 100644
--- a/hotspot/src/share/vm/oops/methodData.hpp
+++ b/hotspot/src/share/vm/oops/methodData.hpp
@@ -190,12 +190,6 @@ public:
void set_header(intptr_t value) {
_header._bits = value;
}
- bool atomic_set_header(intptr_t value) {
- if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) {
- return true;
- }
- return false;
- }
intptr_t header() {
return _header._bits;
}
@@ -2047,10 +2041,12 @@ private:
// Cached hint for bci_to_dp and bci_to_data
int _hint_di;
+ Mutex _extra_data_lock;
+
MethodData(methodHandle method, int size, TRAPS);
public:
static MethodData* allocate(ClassLoaderData* loader_data, methodHandle method, TRAPS);
- MethodData() {}; // For ciMethodData
+ MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData
bool is_methodData() const volatile { return true; }
@@ -2155,7 +2151,7 @@ private:
// What is the index of the first data entry?
int first_di() const { return 0; }
- ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp);
+ ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent);
// Find or create an extra ProfileData:
ProfileData* bci_to_extra_data(int bci, Method* m, bool create_if_missing);
From 9e39a2797d24e49e237f4be847cf01036cae34a3 Mon Sep 17 00:00:00 2001
From: Albert Noll
Date: Wed, 5 Mar 2014 10:20:30 +0100
Subject: [PATCH 027/116] 8036091: compiler/membars/DekkerTest.java fails with
-XX:CICompilerCount=1
Start test with -XX:-TieredCompilation so that one compiler thread works
Reviewed-by: kvn, twisti
---
hotspot/src/share/vm/runtime/arguments.cpp | 2 +-
hotspot/test/compiler/membars/DekkerTest.java | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index 1e02bf0cad8..d6d8583d697 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -2409,7 +2409,7 @@ bool Arguments::check_vm_args_consistency() {
status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
// TieredCompilation needs at least 2 compiler threads.
- const int num_min_compiler_threads = (TieredCompilation) ? 2 : 1;
+ const int num_min_compiler_threads = (TieredCompilation && (TieredStopAtLevel >= CompLevel_full_optimization)) ? 2 : 1;
status &=verify_min_value(CICompilerCount, num_min_compiler_threads, "CICompilerCount");
return status;
diff --git a/hotspot/test/compiler/membars/DekkerTest.java b/hotspot/test/compiler/membars/DekkerTest.java
index ed313576010..f4f2826b6e4 100644
--- a/hotspot/test/compiler/membars/DekkerTest.java
+++ b/hotspot/test/compiler/membars/DekkerTest.java
@@ -25,9 +25,9 @@
* @test
* @bug 8007898
* @summary Incorrect optimization of Memory Barriers in Matcher::post_store_load_barrier().
- * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
- * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
- * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
+ * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
* @author Martin Doerr martin DOT doerr AT sap DOT com
*
* Run 3 times since the failure is intermittent.
From 7bee30f699b32b64fba849476c5c898c59fd41e9 Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Wed, 5 Mar 2014 15:14:25 +0100
Subject: [PATCH 028/116] 8036146: make CPP interpreter build again
Fix build of CPP interpreter on x86 and sparc
Reviewed-by: kvn
---
.../src/cpu/sparc/vm/cppInterpreter_sparc.cpp | 72 +++++++++----------
hotspot/src/cpu/sparc/vm/frame_sparc.cpp | 2 +
.../src/cpu/sparc/vm/interp_masm_sparc.cpp | 35 ++++-----
hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp | 3 +-
.../x86/vm/bytecodeInterpreter_x86.inline.hpp | 2 +-
hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp | 48 +++++++++----
hotspot/src/cpu/x86/vm/frame_x86.cpp | 2 +
hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp | 55 +++++++-------
hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp | 2 +-
hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp | 56 ++++++++-------
hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp | 2 +-
hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp | 2 +
hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp | 2 +
.../vm/interpreter/bytecodeInterpreter.cpp | 2 +-
14 files changed, 159 insertions(+), 126 deletions(-)
diff --git a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
index 371b6aa7f71..1a53471e596 100644
--- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp
@@ -413,16 +413,15 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile
// Update standard invocation counters
__ increment_invocation_counter(Rcounters, O0, G4_scratch);
if (ProfileInterpreter) {
- Address interpreter_invocation_counter(Rcounters, 0,
+ Address interpreter_invocation_counter(Rcounters,
in_bytes(MethodCounters::interpreter_invocation_counter_offset()));
__ ld(interpreter_invocation_counter, G4_scratch);
__ inc(G4_scratch);
__ st(G4_scratch, interpreter_invocation_counter);
}
- Address invocation_limit(G3_scratch, (address)&InvocationCounter::InterpreterInvocationLimit);
- __ sethi(invocation_limit);
- __ ld(invocation_limit, G3_scratch);
+ AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit);
+ __ load_contents(invocation_limit, G3_scratch);
__ cmp(O0, G3_scratch);
__ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow);
__ delayed()->nop();
@@ -439,7 +438,7 @@ address InterpreterGenerator::generate_empty_entry(void) {
// do nothing for empty methods (do not even increment invocation counter)
if ( UseFastEmptyMethods) {
// If we need a safepoint check, generate full interpreter entry.
- Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
+ AddressLiteral sync_state(SafepointSynchronize::address_of_state());
__ load_contents(sync_state, G3_scratch);
__ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
__ br(Assembler::notEqual, false, Assembler::pn, frame_manager_entry);
@@ -471,7 +470,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if ( UseFastAccessorMethods) {
// Check if we need to reach a safepoint and generate full interpreter
// frame if so.
- Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
+ AddressLiteral sync_state(SafepointSynchronize::address_of_state());
__ load_contents(sync_state, G3_scratch);
__ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
__ br(Assembler::notEqual, false, Assembler::pn, slow_path);
@@ -486,8 +485,8 @@ address InterpreterGenerator::generate_accessor_entry(void) {
// read first instruction word and extract bytecode @ 1 and index @ 2
// get first 4 bytes of the bytecodes (big endian!)
- __ ld_ptr(Address(G5_method, 0, in_bytes(Method::const_offset())), G1_scratch);
- __ ld(Address(G1_scratch, 0, in_bytes(ConstMethod::codes_offset())), G1_scratch);
+ __ ld_ptr(Address(G5_method, in_bytes(Method::const_offset())), G1_scratch);
+ __ ld(Address(G1_scratch, in_bytes(ConstMethod::codes_offset())), G1_scratch);
// move index @ 2 far left then to the right most two bytes.
__ sll(G1_scratch, 2*BitsPerByte, G1_scratch);
@@ -590,15 +589,15 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
const Register Gtmp1 = G3_scratch ;
const Register Gtmp2 = G1_scratch;
const Register RconstMethod = Gtmp1;
- const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
- const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address constMethod(G5_method, in_bytes(Method::const_offset()));
+ const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
bool inc_counter = UseCompiler || CountCompiledCalls;
// make sure registers are different!
assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
- const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
+ const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
Label Lentry;
__ bind(Lentry);
@@ -643,7 +642,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// At this point Lstate points to new interpreter state
//
- const Address do_not_unlock_if_synchronized(G2_thread, 0,
+ const Address do_not_unlock_if_synchronized(G2_thread,
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
// Since at this point in the method invocation the exception handler
// would try to exit the monitor of synchronized methods which hasn't
@@ -717,17 +716,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
{ Label L;
__ ld_ptr(STATE(_method), G5_method);
- __ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch);
+ __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch);
__ tst(G3_scratch);
__ brx(Assembler::notZero, false, Assembler::pt, L);
__ delayed()->nop();
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), G5_method, false);
__ ld_ptr(STATE(_method), G5_method);
- Address exception_addr(G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
+ Address exception_addr(G2_thread, in_bytes(Thread::pending_exception_offset()));
__ ld_ptr(exception_addr, G3_scratch);
__ br_notnull_short(G3_scratch, Assembler::pn, pending_exception_present);
- __ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch);
+ __ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch);
__ bind(L);
}
@@ -771,13 +770,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
__ br( Assembler::zero, false, Assembler::pt, not_static);
__ delayed()->
// get native function entry point(O0 is a good temp until the very end)
- ld_ptr(Address(G5_method, 0, in_bytes(Method::native_function_offset())), O0);
+ ld_ptr(Address(G5_method, in_bytes(Method::native_function_offset())), O0);
// for static methods insert the mirror argument
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
- __ ld_ptr(Address(G5_method, 0, in_bytes(Method:: const_offset())), O1);
- __ ld_ptr(Address(O1, 0, in_bytes(ConstMethod::constants_offset())), O1);
- __ ld_ptr(Address(O1, 0, ConstantPool::pool_holder_offset_in_bytes()), O1);
+ __ ld_ptr(Address(G5_method, in_bytes(Method:: const_offset())), O1);
+ __ ld_ptr(Address(O1, in_bytes(ConstMethod::constants_offset())), O1);
+ __ ld_ptr(Address(O1, ConstantPool::pool_holder_offset_in_bytes()), O1);
__ ld_ptr(O1, mirror_offset, O1);
// where the mirror handle body is allocated:
#ifdef ASSERT
@@ -831,18 +830,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// flush the windows now. We don't care about the current (protection) frame
// only the outer frames
- __ flush_windows();
+ __ flushw();
// mark windows as flushed
Address flags(G2_thread,
- 0,
in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset()));
__ set(JavaFrameAnchor::flushed, G3_scratch);
__ st(G3_scratch, flags);
// Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready.
- Address thread_state(G2_thread, 0, in_bytes(JavaThread::thread_state_offset()));
+ Address thread_state(G2_thread, in_bytes(JavaThread::thread_state_offset()));
#ifdef ASSERT
{ Label L;
__ ld(thread_state, G3_scratch);
@@ -867,7 +865,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// Block, if necessary, before resuming in _thread_in_Java state.
// In order for GC to work, don't clear the last_Java_sp until after blocking.
{ Label no_block;
- Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
+ AddressLiteral sync_state(SafepointSynchronize::address_of_state());
// Switch thread to "native transition" state before reading the synchronization state.
// This additional state is necessary because reading and testing the synchronization
@@ -890,7 +888,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
Label L;
- Address suspend_state(G2_thread, 0, in_bytes(JavaThread::suspend_flags_offset()));
+ Address suspend_state(G2_thread, in_bytes(JavaThread::suspend_flags_offset()));
__ br(Assembler::notEqual, false, Assembler::pn, L);
__ delayed()->
ld(suspend_state, G3_scratch);
@@ -965,7 +963,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// handle exceptions (exception handling will handle unlocking!)
{ Label L;
- Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
+ Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset()));
__ ld_ptr(exception_addr, Gtemp);
__ tst(Gtemp);
@@ -1055,8 +1053,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
assert_different_registers(state, prev_state);
assert_different_registers(prev_state, G3_scratch);
const Register Gtmp = G3_scratch;
- const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
- const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
+ const Address constMethod (G5_method, in_bytes(Method::const_offset()));
+ const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
// slop factor is two extra slots on the expression stack so that
// we always have room to store a result when returning from a call without parameters
@@ -1075,7 +1073,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
if (native) {
const Register RconstMethod = Gtmp;
- const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
__ ld_ptr(constMethod, RconstMethod);
__ lduh( size_of_parameters, Gtmp );
__ calc_mem_param_words(Gtmp, Gtmp); // space for native call parameters passed on the stack in words
@@ -1246,8 +1244,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
if (init_value != noreg) {
Label clear_loop;
const Register RconstMethod = O1;
- const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
- const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
+ const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset()));
// NOTE: If you change the frame layout, this code will need to
// be updated!
@@ -1496,11 +1494,11 @@ void CppInterpreterGenerator::adjust_callers_stack(Register args) {
//
// assert_different_registers(state, prev_state);
const Register Gtmp = G3_scratch;
- const RconstMethod = G3_scratch;
+ const Register RconstMethod = G3_scratch;
const Register tmp = O2;
- const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
- const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
- const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
+ const Address constMethod(G5_method, in_bytes(Method::const_offset()));
+ const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset()));
__ ld_ptr(constMethod, RconstMethod);
__ lduh(size_of_parameters, tmp);
@@ -1555,8 +1553,8 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
const Register Gtmp1 = G3_scratch;
// const Register Lmirror = L1; // native mirror (native calls only)
- const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
- const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
+ const Address constMethod (G5_method, in_bytes(Method::const_offset()));
+ const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
address entry_point = __ pc();
__ mov(G0, prevState); // no current activation
@@ -1709,7 +1707,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
// We want exception in the thread no matter what we ultimately decide about frame type.
- Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
+ Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset()));
__ verify_thread();
__ st_ptr(O0, exception_addr);
diff --git a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp
index 6ce05bdfce1..29b37f006a5 100644
--- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp
@@ -827,6 +827,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
}
if (is_interpreted_frame()) {
+#ifndef CC_INTERP
DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp);
DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp);
DESCRIBE_FP_OFFSET(interpreter_frame_padding);
@@ -837,6 +838,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
if ((esp >= sp()) && (esp < fp())) {
values.describe(-1, esp, "*Lesp");
}
+#endif
}
if (!is_compiled_frame()) {
diff --git a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
index c22f20a23d4..9d4d13bf663 100644
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp
@@ -2497,6 +2497,24 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis
void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth);
}
+
+
+// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
+void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
+ int increment, int mask,
+ Register scratch1, Register scratch2,
+ Condition cond, Label *where) {
+ ld(counter_addr, scratch1);
+ add(scratch1, increment, scratch1);
+ if (is_simm13(mask)) {
+ andcc(scratch1, mask, G0);
+ } else {
+ set(mask, scratch2);
+ andcc(scratch1, scratch2, G0);
+ }
+ br(cond, false, Assembler::pn, *where);
+ delayed()->st(scratch1, counter_addr);
+}
#endif /* CC_INTERP */
// Inline assembly for:
@@ -2646,20 +2664,3 @@ void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_na
}
#endif // CC_INTERP
}
-
-// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
-void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
- int increment, int mask,
- Register scratch1, Register scratch2,
- Condition cond, Label *where) {
- ld(counter_addr, scratch1);
- add(scratch1, increment, scratch1);
- if (is_simm13(mask)) {
- andcc(scratch1, mask, G0);
- } else {
- set(mask, scratch2);
- andcc(scratch1, scratch2, G0);
- }
- br(cond, false, Assembler::pn, *where);
- delayed()->st(scratch1, counter_addr);
-}
diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
index f5ac37cf6fa..c15c3c0994f 100644
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "code/codeCache.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_sparc.hpp"
#include "oops/oop.inline.hpp"
diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp
index 4f60b455801..d205f1db79a 100644
--- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp
+++ b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp
@@ -250,7 +250,7 @@ inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) {
return op1 - op2;
}
-inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
+inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
return ((juint) op1) >> (op2 & 0x1f);
}
diff --git a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp
index e669f5b6638..0ddf854f364 100644
--- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp
@@ -574,7 +574,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile
MethodCounters::invocation_counter_offset() +
InvocationCounter::counter_offset());
const Address backedge_counter (rax,
- MethodCounter::backedge_counter_offset() +
+ MethodCounters::backedge_counter_offset() +
InvocationCounter::counter_offset());
__ get_method_counters(rbx, rax, done);
@@ -982,16 +982,18 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
// to save/restore.
address entry_point = __ pc();
- const Address constMethod (rbx, Method::const_offset());
const Address access_flags (rbx, Method::access_flags_offset());
- const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
// rsi/r13 == state/locals rdi == prevstate
const Register locals = rdi;
// get parameter size (always needed)
- __ movptr(rcx, constMethod);
- __ load_unsigned_short(rcx, size_of_parameters);
+ {
+ const Address constMethod (rbx, Method::const_offset());
+ const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
+ __ movptr(rcx, constMethod);
+ __ load_unsigned_short(rcx, size_of_parameters);
+ }
// rbx: Method*
// rcx: size of parameters
@@ -1111,14 +1113,16 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
const Register method = rbx;
const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rdi);
const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); // rcx|rscratch1
- const Address constMethod (method, Method::const_offset());
- const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset());
- // allocate space for parameters
+ // allocate space for parameters
__ movptr(method, STATE(_method));
__ verify_method_ptr(method);
- __ movptr(t, constMethod);
- __ load_unsigned_short(t, size_of_parameters);
+ {
+ const Address constMethod (method, Method::const_offset());
+ const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset());
+ __ movptr(t, constMethod);
+ __ load_unsigned_short(t, size_of_parameters);
+ }
__ shll(t, 2);
#ifdef _LP64
__ subptr(rsp, t);
@@ -2221,7 +2225,6 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
- case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sin : // fall thru
case Interpreter::java_lang_math_cos : // fall thru
@@ -2229,7 +2232,10 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
case Interpreter::java_lang_math_abs : // fall thru
case Interpreter::java_lang_math_log : // fall thru
case Interpreter::java_lang_math_log10 : // fall thru
- case Interpreter::java_lang_math_sqrt : entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break;
+ case Interpreter::java_lang_math_sqrt : // fall thru
+ case Interpreter::java_lang_math_pow : // fall thru
+ case Interpreter::java_lang_math_exp : // fall thru
+ entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break;
case Interpreter::java_lang_ref_reference_get
: entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break;
default : ShouldNotReachHere(); break;
@@ -2451,4 +2457,22 @@ int AbstractInterpreter::layout_activation(Method* method,
return frame_size/BytesPerWord;
}
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ switch (method_kind(m)) {
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+ case Interpreter::java_lang_math_tan : // fall thru
+ case Interpreter::java_lang_math_abs : // fall thru
+ case Interpreter::java_lang_math_log : // fall thru
+ case Interpreter::java_lang_math_log10 : // fall thru
+ case Interpreter::java_lang_math_sqrt : // fall thru
+ case Interpreter::java_lang_math_pow : // fall thru
+ case Interpreter::java_lang_math_exp :
+ return false;
+ default:
+ return true;
+ }
+}
+
+
#endif // CC_INTERP (all)
diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp
index 4e83863a9f9..deeb48a44bb 100644
--- a/hotspot/src/cpu/x86/vm/frame_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp
@@ -687,6 +687,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
void frame::describe_pd(FrameValues& values, int frame_no) {
if (is_interpreted_frame()) {
+#ifndef CC_INTERP
DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp);
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
DESCRIBE_FP_OFFSET(interpreter_frame_method);
@@ -695,6 +696,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
DESCRIBE_FP_OFFSET(interpreter_frame_bcx);
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
+#endif
}
}
#endif
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
index b6f2438db83..92f58b4d61a 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
@@ -266,20 +266,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, R
addptr(cache, tmp); // construct pointer to cache entry
}
-void InterpreterMacroAssembler::get_method_counters(Register method,
- Register mcs, Label& skip) {
- Label has_counters;
- movptr(mcs, Address(method, Method::method_counters_offset()));
- testptr(mcs, mcs);
- jcc(Assembler::notZero, has_counters);
- call_VM(noreg, CAST_FROM_FN_PTR(address,
- InterpreterRuntime::build_method_counters), method);
- movptr(mcs, Address(method,Method::method_counters_offset()));
- testptr(mcs, mcs);
- jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
- bind(has_counters);
-}
-
// Load object from cpool->resolved_references(index)
void InterpreterMacroAssembler::load_resolved_reference_at_index(
Register result, Register index) {
@@ -678,6 +664,20 @@ void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_a
#endif /* !CC_INTERP */
+void InterpreterMacroAssembler::get_method_counters(Register method,
+ Register mcs, Label& skip) {
+ Label has_counters;
+ movptr(mcs, Address(method, Method::method_counters_offset()));
+ testptr(mcs, mcs);
+ jcc(Assembler::notZero, has_counters);
+ call_VM(noreg, CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::build_method_counters), method);
+ movptr(mcs, Address(method,Method::method_counters_offset()));
+ testptr(mcs, mcs);
+ jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
+ bind(has_counters);
+}
+
// Lock object
//
@@ -1359,6 +1359,19 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth);
}
+// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
+void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
+ int increment, int mask,
+ Register scratch, bool preloaded,
+ Condition cond, Label* where) {
+ if (!preloaded) {
+ movl(scratch, counter_addr);
+ }
+ incrementl(scratch, increment);
+ movl(counter_addr, scratch);
+ andl(scratch, mask);
+ jcc(cond, *where);
+}
#endif /* CC_INTERP */
@@ -1430,17 +1443,3 @@ void InterpreterMacroAssembler::notify_method_exit(
NOT_CC_INTERP(pop(state));
}
}
-
-// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
-void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
- int increment, int mask,
- Register scratch, bool preloaded,
- Condition cond, Label* where) {
- if (!preloaded) {
- movl(scratch, counter_addr);
- }
- incrementl(scratch, increment);
- movl(counter_addr, scratch);
- andl(scratch, mask);
- jcc(cond, *where);
-}
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
index 19ff288bfee..88f01fc5852 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
@@ -77,7 +77,6 @@
void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
- void get_method_counters(Register method, Register mcs, Label& skip);
// load cpool->resolved_references(index);
void load_resolved_reference_at_index(Register result, Register index);
@@ -156,6 +155,7 @@
bool install_monitor_exception = true,
bool notify_jvmdi = true);
#endif /* !CC_INTERP */
+ void get_method_counters(Register method, Register mcs, Label& skip);
// Debugging
void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
index 520c872a604..356106e946f 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
@@ -271,20 +271,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
addptr(cache, tmp); // construct pointer to cache entry
}
-void InterpreterMacroAssembler::get_method_counters(Register method,
- Register mcs, Label& skip) {
- Label has_counters;
- movptr(mcs, Address(method, Method::method_counters_offset()));
- testptr(mcs, mcs);
- jcc(Assembler::notZero, has_counters);
- call_VM(noreg, CAST_FROM_FN_PTR(address,
- InterpreterRuntime::build_method_counters), method);
- movptr(mcs, Address(method,Method::method_counters_offset()));
- testptr(mcs, mcs);
- jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
- bind(has_counters);
-}
-
// Load object from cpool->resolved_references(index)
void InterpreterMacroAssembler::load_resolved_reference_at_index(
Register result, Register index) {
@@ -676,6 +662,21 @@ void InterpreterMacroAssembler::remove_activation(
#endif // C_INTERP
+void InterpreterMacroAssembler::get_method_counters(Register method,
+ Register mcs, Label& skip) {
+ Label has_counters;
+ movptr(mcs, Address(method, Method::method_counters_offset()));
+ testptr(mcs, mcs);
+ jcc(Assembler::notZero, has_counters);
+ call_VM(noreg, CAST_FROM_FN_PTR(address,
+ InterpreterRuntime::build_method_counters), method);
+ movptr(mcs, Address(method,Method::method_counters_offset()));
+ testptr(mcs, mcs);
+ jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
+ bind(has_counters);
+}
+
+
// Lock object
//
// Args:
@@ -1423,6 +1424,20 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) {
void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
}
+
+// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
+void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
+ int increment, int mask,
+ Register scratch, bool preloaded,
+ Condition cond, Label* where) {
+ if (!preloaded) {
+ movl(scratch, counter_addr);
+ }
+ incrementl(scratch, increment);
+ movl(counter_addr, scratch);
+ andl(scratch, mask);
+ jcc(cond, *where);
+}
#endif // !CC_INTERP
@@ -1491,16 +1506,3 @@ void InterpreterMacroAssembler::notify_method_exit(
}
}
-// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
-void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
- int increment, int mask,
- Register scratch, bool preloaded,
- Condition cond, Label* where) {
- if (!preloaded) {
- movl(scratch, counter_addr);
- }
- incrementl(scratch, increment);
- movl(counter_addr, scratch);
- andl(scratch, mask);
- jcc(cond, *where);
-}
diff --git a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
index 36bd779ef9b..9186009fa9a 100644
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
@@ -99,7 +99,6 @@
void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
- void get_method_counters(Register method, Register mcs, Label& skip);
// load cpool->resolved_references(index);
void load_resolved_reference_at_index(Register result, Register index);
@@ -172,6 +171,7 @@
bool install_monitor_exception = true,
bool notify_jvmdi = true);
#endif // CC_INTERP
+ void get_method_counters(Register method, Register mcs, Label& skip);
// Object locking
void lock_object (Register lock_reg);
diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
index 865801e3de7..3c66bf4fb45 100644
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp
@@ -229,10 +229,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
// abstract method entry
+#ifndef CC_INTERP
// pop return address, reset last_sp to NULL
__ empty_expression_stack();
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
+#endif
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
diff --git a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
index bc5229b997d..02ee74506bb 100644
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp
@@ -310,10 +310,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
// abstract method entry
+#ifndef CC_INTERP
// pop return address, reset last_sp to NULL
__ empty_expression_stack();
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
+#endif
// throw exception
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
index 06261c804de..9453b50febb 100644
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp
@@ -3475,7 +3475,7 @@ BytecodeInterpreter::print() {
tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult);
tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult);
#endif
-#if !defined(ZERO)
+#if !defined(ZERO) && defined(PPC)
tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp);
#endif // !ZERO
tty->print_cr("self_link: " INTPTR_FORMAT, (uintptr_t) this->_self_link);
From 8c7d064ee8be6be3bbd83345c7098803809ce57d Mon Sep 17 00:00:00 2001
From: Jon Masamitsu
Date: Wed, 5 Mar 2014 07:34:35 -0800
Subject: [PATCH 029/116] 7098155: Resize young gen at full collections for
UseParallelGC
Reviewed-by: tschatzl
---
.../parallelScavenge/psMarkSweep.cpp | 18 ++++++++++++------
.../parallelScavenge/psParallelCompact.cpp | 19 +++++++++++++------
2 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
index 39d88816718..ca2037cb6f9 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
@@ -280,6 +280,16 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
if (UseAdaptiveGenerationSizePolicyAtMajorCollection &&
((gc_cause != GCCause::_java_lang_system_gc) ||
UseAdaptiveSizePolicyWithSystemGC)) {
+ // Swap the survivor spaces if from_space is empty. The
+ // resize_young_gen() called below is normally used after
+ // a successful young GC and swapping of survivor spaces;
+ // otherwise, it will fail to resize the young gen with
+ // the current implementation.
+ if (young_gen->from_space()->is_empty()) {
+ young_gen->from_space()->clear(SpaceDecorator::Mangle);
+ young_gen->swap_spaces();
+ }
+
// Calculate optimal free space amounts
assert(young_gen->max_size() >
young_gen->from_space()->capacity_in_bytes() +
@@ -318,12 +328,8 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
heap->resize_old_gen(size_policy->calculated_old_free_size_in_bytes());
- // Don't resize the young generation at an major collection. A
- // desired young generation size may have been calculated but
- // resizing the young generation complicates the code because the
- // resizing of the old generation may have moved the boundary
- // between the young generation and the old generation. Let the
- // young generation resizing happen at the minor collections.
+ heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(),
+ size_policy->calculated_survivor_size_in_bytes());
}
if (PrintAdaptiveSizePolicy) {
gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ",
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
index f2e83ca21df..31ee8bc5938 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
@@ -43,6 +43,7 @@
#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
+#include "gc_implementation/shared/spaceDecorator.hpp"
#include "gc_interface/gcCause.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/referencePolicy.hpp"
@@ -2115,6 +2116,16 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
if (UseAdaptiveGenerationSizePolicyAtMajorCollection &&
((gc_cause != GCCause::_java_lang_system_gc) ||
UseAdaptiveSizePolicyWithSystemGC)) {
+ // Swap the survivor spaces if from_space is empty. The
+ // resize_young_gen() called below is normally used after
+ // a successful young GC and swapping of survivor spaces;
+ // otherwise, it will fail to resize the young gen with
+ // the current implementation.
+ if (young_gen->from_space()->is_empty()) {
+ young_gen->from_space()->clear(SpaceDecorator::Mangle);
+ young_gen->swap_spaces();
+ }
+
// Calculate optimal free space amounts
assert(young_gen->max_size() >
young_gen->from_space()->capacity_in_bytes() +
@@ -2154,12 +2165,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
heap->resize_old_gen(
size_policy->calculated_old_free_size_in_bytes());
- // Don't resize the young generation at an major collection. A
- // desired young generation size may have been calculated but
- // resizing the young generation complicates the code because the
- // resizing of the old generation may have moved the boundary
- // between the young generation and the old generation. Let the
- // young generation resizing happen at the minor collections.
+ heap->resize_young_gen(size_policy->calculated_eden_size_in_bytes(),
+ size_policy->calculated_survivor_size_in_bytes());
}
if (PrintAdaptiveSizePolicy) {
gclog_or_tty->print_cr("AdaptiveSizeStop: collection: %d ",
From eedf369513ed4f601842be24dc5471ca72d92a97 Mon Sep 17 00:00:00 2001
From: Mikhailo Seledtsov
Date: Wed, 5 Mar 2014 12:31:09 -0500
Subject: [PATCH 030/116] 8033990: Add message to verbose output to indicate
when JVM was unable to use shared archive (with -Xshare:auto)
Added message to indicate when sharing was attempted but failed
Reviewed-by: coleenp, ctornqvi
---
hotspot/src/share/vm/memory/filemap.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp
index 8eb5f452495..1420c279036 100644
--- a/hotspot/src/share/vm/memory/filemap.cpp
+++ b/hotspot/src/share/vm/memory/filemap.cpp
@@ -78,6 +78,10 @@ void FileMapInfo::fail_continue(const char *msg, ...) {
va_start(ap, msg);
if (RequireSharedSpaces) {
fail(msg, ap);
+ } else {
+ if (PrintSharedSpaces) {
+ tty->print_cr("UseSharedSpaces: %s", msg);
+ }
}
va_end(ap);
UseSharedSpaces = false;
From 533560cb3e71b7726313d90945106116692b4379 Mon Sep 17 00:00:00 2001
From: Vladimir Kozlov
Date: Wed, 5 Mar 2014 16:21:22 -0800
Subject: [PATCH 031/116] 8035983: Fix "Native frames:" in crash report (hs_err
file)
Check fr.sender_sp() in java thread instead of os::is_first_C_frame(&fr).
Reviewed-by: twisti, coleenp
---
hotspot/src/share/vm/utilities/vmError.cpp | 23 ++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp
index 4b0953ae499..e950d338681 100644
--- a/hotspot/src/share/vm/utilities/vmError.cpp
+++ b/hotspot/src/share/vm/utilities/vmError.cpp
@@ -592,13 +592,24 @@ void VMError::report(outputStream* st) {
st->cr();
// Compiled code may use EBP register on x86 so it looks like
// non-walkable C frame. Use frame.sender() for java frames.
- if (_thread && _thread->is_Java_thread() && fr.is_java_frame()) {
- RegisterMap map((JavaThread*)_thread, false); // No update
- fr = fr.sender(&map);
- continue;
+ if (_thread && _thread->is_Java_thread()) {
+ // Catch very first native frame by using stack address.
+ // For JavaThread stack_base and stack_size should be set.
+ if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) {
+ break;
+ }
+ if (fr.is_java_frame()) {
+ RegisterMap map((JavaThread*)_thread, false); // No update
+ fr = fr.sender(&map);
+ } else {
+ fr = os::get_sender_for_C_frame(&fr);
+ }
+ } else {
+ // is_first_C_frame() does only simple checks for frame pointer,
+ // it will pass if java compiled code has a pointer in EBP.
+ if (os::is_first_C_frame(&fr)) break;
+ fr = os::get_sender_for_C_frame(&fr);
}
- if (os::is_first_C_frame(&fr)) break;
- fr = os::get_sender_for_C_frame(&fr);
}
if (count > StackPrintLimit) {
From 54177912e8471ebf8a418b199926f4925187a2fd Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Thu, 6 Mar 2014 12:45:59 +0400
Subject: [PATCH 032/116] 8028482: [TESTBUG] tests that use JMX should be in
need_compact3 test group
Reviewed-by: roland, sla, dholmes
---
hotspot/test/TEST.groups | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups
index 946cb2be8cf..676d859686d 100644
--- a/hotspot/test/TEST.groups
+++ b/hotspot/test/TEST.groups
@@ -130,7 +130,9 @@ needs_compact3 = \
gc/arguments/TestG1HeapRegionSize.java \
gc/metaspace/TestMetaspaceMemoryPool.java \
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
- serviceability/threads/TestFalseDeadLock.java
+ serviceability/threads/TestFalseDeadLock.java \
+ compiler/tiered/NonTieredLevelsTest.java \
+ compiler/tiered/TieredLevelsTest.java
# Compact 2 adds full VM tests
compact2 = \
From 4f2175f0881cacd9cbef1565f1fb4d16b676c205 Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Thu, 6 Mar 2014 12:46:04 +0400
Subject: [PATCH 033/116] 8027257: [TESTBUG] compiler/ciReplay/TestVM.sh :
Error: Could not find or load main class negative_test
Reviewed-by: roland, kvn
---
hotspot/test/compiler/ciReplay/TestVM.sh | 2 +-
hotspot/test/compiler/ciReplay/common.sh | 3 +--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/hotspot/test/compiler/ciReplay/TestVM.sh b/hotspot/test/compiler/ciReplay/TestVM.sh
index e6c3cc56946..6154466671d 100644
--- a/hotspot/test/compiler/ciReplay/TestVM.sh
+++ b/hotspot/test/compiler/ciReplay/TestVM.sh
@@ -78,8 +78,8 @@ then
positive_test `expr $stop_level + 50` "TIERED LEVEL $stop_level :: REPLAY" \
"-XX:TieredStopAtLevel=$stop_level"
stop_level=`expr $stop_level + 1`
+ cleanup
done
- cleanup
fi
echo TEST PASSED
diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh
index e03acaa8b30..608f68e551a 100644
--- a/hotspot/test/compiler/ciReplay/common.sh
+++ b/hotspot/test/compiler/ciReplay/common.sh
@@ -99,13 +99,12 @@ common_tests() {
# $2 - non-tiered comp_level
nontiered_tests() {
level=`grep "^compile " $replay_data | awk '{print $6}'`
- # is level available in non-tiere
+ # is level available in non-tiered
if [ "$level" -eq $2 ]
then
positive_test $1 "NON-TIERED :: AVAILABLE COMP_LEVEL" \
-XX:-TieredCompilation
else
- negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
-XX:-TieredCompilation
fi
From 8439d7fa51ff0a3ffaacbb3127cd2c52d2588197 Mon Sep 17 00:00:00 2001
From: Igor Ignatyev
Date: Thu, 6 Mar 2014 12:47:45 +0400
Subject: [PATCH 034/116] 8027124: [TESTBUG] NonTieredLevelsTest:
java.lang.RuntimeException: private TestCase$Helper(java.lang.Object) must be
osr_compiled
Reviewed-by: kvn, roland
---
.../compiler/tiered/NonTieredLevelsTest.java | 5 ++++-
.../test/compiler/tiered/TieredLevelsTest.java | 5 ++++-
.../compiler/whitebox/CompilerWhiteBoxTest.java | 16 +++++++++++++++-
.../compiler/whitebox/DeoptimizeAllTest.java | 9 +++------
.../compiler/whitebox/DeoptimizeMethodTest.java | 9 +++------
.../whitebox/IsMethodCompilableTest.java | 7 ++-----
.../whitebox/MakeMethodNotCompilableTest.java | 9 +++------
7 files changed, 34 insertions(+), 26 deletions(-)
diff --git a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java
index 715d32a8944..13411a0dd73 100644
--- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java
+++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -70,6 +70,9 @@ public class NonTieredLevelsTest extends CompLevelsTest {
@Override
protected void test() throws Exception {
+ if (skipXcompOSR()) {
+ return;
+ }
checkNotCompiled();
compile();
checkCompiled();
diff --git a/hotspot/test/compiler/tiered/TieredLevelsTest.java b/hotspot/test/compiler/tiered/TieredLevelsTest.java
index 675a394498a..9fb2254d0b5 100644
--- a/hotspot/test/compiler/tiered/TieredLevelsTest.java
+++ b/hotspot/test/compiler/tiered/TieredLevelsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -51,6 +51,9 @@ public class TieredLevelsTest extends CompLevelsTest {
@Override
protected void test() throws Exception {
+ if (skipXcompOSR()) {
+ return;
+ }
checkNotCompiled();
compile();
checkCompiled();
diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
index 97dad5bf704..c199c2a6a67 100644
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -403,6 +403,20 @@ public abstract class CompilerWhiteBoxTest {
/** flag for OSR test case */
boolean isOsr();
}
+
+ /**
+ * @return {@code true} if the current test case is OSR and the mode is
+ * Xcomp, otherwise {@code false}
+ */
+ protected boolean skipXcompOSR() {
+ boolean result = testCase.isOsr()
+ && CompilerWhiteBoxTest.MODE.startsWith("compiled ");
+ if (result && IS_VERBOSE) {
+ System.err.printf("Warning: %s is not applicable in %s%n",
+ testCase.name(), CompilerWhiteBoxTest.MODE);
+ }
+ return result;
+ }
}
enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase {
diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java
index 350c99c8f5c..ea4e36400eb 100644
--- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java
+++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -51,11 +51,8 @@ public class DeoptimizeAllTest extends CompilerWhiteBoxTest {
*/
@Override
protected void test() throws Exception {
- if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
- "compiled ")) {
- System.err.printf("Warning: %s is not applicable in %s%n",
- testCase.name(), CompilerWhiteBoxTest.MODE);
- return;
+ if (skipXcompOSR()) {
+ return;
}
compile();
checkCompiled();
diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java
index 565a5b91cd7..0b9ffd2d9db 100644
--- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java
+++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -51,11 +51,8 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest {
*/
@Override
protected void test() throws Exception {
- if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
- "compiled ")) {
- System.err.printf("Warning: %s is not applicable in %s%n",
- testCase.name(), CompilerWhiteBoxTest.MODE);
- return;
+ if (skipXcompOSR()) {
+ return;
}
compile();
checkCompiled();
diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
index 83d88669735..88e5cd835e4 100644
--- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
+++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -77,10 +77,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
return;
}
- if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
- "compiled ")) {
- System.err.printf("Warning: %s is not applicable in %s%n",
- testCase.name(), CompilerWhiteBoxTest.MODE);
+ if (skipXcompOSR()) {
return;
}
if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java
index cbd65da45bd..d6586879778 100644
--- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java
+++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -53,11 +53,8 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest {
*/
@Override
protected void test() throws Exception {
- if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
- "compiled ")) {
- System.err.printf("Warning: %s is not applicable in %s%n",
- testCase.name(), CompilerWhiteBoxTest.MODE);
- return;
+ if (skipXcompOSR()) {
+ return;
}
checkNotCompiled();
if (!isCompilable()) {
From d5ff84f8b3e1027a84af27f13c221bce2def07bf Mon Sep 17 00:00:00 2001
From: Roland Westrelin
Date: Thu, 6 Mar 2014 11:11:04 +0100
Subject: [PATCH 035/116] 8032633: Enable type speculation by default
Enable type speculation
Reviewed-by: kvn
---
hotspot/src/share/vm/opto/c2_globals.hpp | 2 +-
.../test/compiler/types/TestMeetTopArrayExactConstantArray.java | 2 +-
.../test/compiler/types/TestSpeculationFailedHigherEqual.java | 2 +-
hotspot/test/compiler/types/TypeSpeculation.java | 2 +-
.../test/compiler/uncommontrap/TestSpecTrapClassUnloading.java | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp
index 3064b2390f1..0db9dab8104 100644
--- a/hotspot/src/share/vm/opto/c2_globals.hpp
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp
@@ -650,7 +650,7 @@
experimental(bool, ReplaceInParentMaps, false, \
"Propagate type improvements in callers of inlinee if possible") \
\
- experimental(bool, UseTypeSpeculation, false, \
+ product(bool, UseTypeSpeculation, true, \
"Speculatively propagate types from profiles") \
\
diagnostic(bool, UseInlineDepthForSpeculativeTypes, true, \
diff --git a/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java b/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java
index 56b19b31713..4ec6e7b03af 100644
--- a/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java
+++ b/hotspot/test/compiler/types/TestMeetTopArrayExactConstantArray.java
@@ -25,7 +25,7 @@
* @test
* @bug 8027571
* @summary meet of TopPTR exact array with constant array is not symmetric
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray
*
*/
diff --git a/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java b/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java
index 9579dce6e40..70d5566ad33 100644
--- a/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java
+++ b/hotspot/test/compiler/types/TestSpeculationFailedHigherEqual.java
@@ -25,7 +25,7 @@
* @test
* @bug 8027422
* @summary type methods shouldn't always operate on speculative part
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual
*
*/
diff --git a/hotspot/test/compiler/types/TypeSpeculation.java b/hotspot/test/compiler/types/TypeSpeculation.java
index 0a9c8e94d95..6f146b84ede 100644
--- a/hotspot/test/compiler/types/TypeSpeculation.java
+++ b/hotspot/test/compiler/types/TypeSpeculation.java
@@ -25,7 +25,7 @@
* @test
* @bug 8024070
* @summary Test that type speculation doesn't cause incorrect execution
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation TypeSpeculation
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation TypeSpeculation
*
*/
diff --git a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
index e660ad5e56d..fcdd592263d 100644
--- a/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
+++ b/hotspot/test/compiler/uncommontrap/TestSpecTrapClassUnloading.java
@@ -25,7 +25,7 @@
* @test
* @bug 8031752
* @summary speculative traps need to be cleaned up at GC
- * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
*
*/
From bd8255eaa4c38f4c9f8341e3157fbe3351d8c26d Mon Sep 17 00:00:00 2001
From: Vladimir Ivanov
Date: Thu, 6 Mar 2014 09:53:14 -0800
Subject: [PATCH 036/116] 8036667: "assert(adr->is_AddP() &&
adr->in(AddPNode::Offset)->is_Con()) failed: offset is a constant" with
FoldStableValues on
Reviewed-by: kvn
---
hotspot/src/share/vm/opto/memnode.cpp | 53 +++++++++++++--------------
1 file changed, 25 insertions(+), 28 deletions(-)
diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp
index 8097eade89f..3a6d4998b06 100644
--- a/hotspot/src/share/vm/opto/memnode.cpp
+++ b/hotspot/src/share/vm/opto/memnode.cpp
@@ -1593,35 +1593,33 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls,
// Try to constant-fold a stable array element.
static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
+ assert(ary->const_oop(), "array should be constant");
assert(ary->is_stable(), "array should be stable");
- if (ary->const_oop() != NULL) {
- // Decode the results of GraphKit::array_element_address.
- ciArray* aobj = ary->const_oop()->as_array();
- ciConstant con = aobj->element_value_by_offset(off);
+ // Decode the results of GraphKit::array_element_address.
+ ciArray* aobj = ary->const_oop()->as_array();
+ ciConstant con = aobj->element_value_by_offset(off);
- if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
- const Type* con_type = Type::make_from_constant(con);
- if (con_type != NULL) {
- if (con_type->isa_aryptr()) {
- // Join with the array element type, in case it is also stable.
- int dim = ary->stable_dimension();
- con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
- }
- if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
- con_type = con_type->make_narrowoop();
- }
-#ifndef PRODUCT
- if (TraceIterativeGVN) {
- tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
- con_type->dump(); tty->cr();
- }
-#endif //PRODUCT
- return con_type;
+ if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+ const Type* con_type = Type::make_from_constant(con);
+ if (con_type != NULL) {
+ if (con_type->isa_aryptr()) {
+ // Join with the array element type, in case it is also stable.
+ int dim = ary->stable_dimension();
+ con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
}
+ if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
+ con_type = con_type->make_narrowoop();
+ }
+#ifndef PRODUCT
+ if (TraceIterativeGVN) {
+ tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
+ con_type->dump(); tty->cr();
+ }
+#endif //PRODUCT
+ return con_type;
}
}
-
return NULL;
}
@@ -1641,7 +1639,7 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
// Try to guess loaded type from pointer type
if (tp->isa_aryptr()) {
const TypeAryPtr* ary = tp->is_aryptr();
- const Type *t = ary->elem();
+ const Type* t = ary->elem();
// Determine whether the reference is beyond the header or not, by comparing
// the offset against the offset of the start of the array's data.
@@ -1653,10 +1651,9 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
// Try to constant-fold a stable array element.
- if (FoldStableValues && ary->is_stable()) {
- // Make sure the reference is not into the header
- if (off_beyond_header && off != Type::OffsetBot) {
- assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant");
+ if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) {
+ // Make sure the reference is not into the header and the offset is constant
+ if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) {
const Type* con_type = fold_stable_ary_elem(ary, off, memory_type());
if (con_type != NULL) {
return con_type;
From f90699ff1671ca7706f0c8fe7c1a562d5790d266 Mon Sep 17 00:00:00 2001
From: Alexander Smundak
Date: Thu, 6 Mar 2014 10:55:28 -0800
Subject: [PATCH 037/116] 8035647: PPC64: Support for elf v2 abi
ELFv2 ABI used by the little endian PowerPC64 on Linux.
Reviewed-by: kvn
---
hotspot/src/cpu/ppc/vm/assembler_ppc.hpp | 4 +
.../src/cpu/ppc/vm/assembler_ppc.inline.hpp | 2 +
hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp | 11 ++-
hotspot/src/cpu/ppc/vm/frame_ppc.hpp | 36 +++----
hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp | 4 +
hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp | 6 +-
hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 75 ++++++++++++---
hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 26 +++++-
.../cpu/ppc/vm/macroAssembler_ppc.inline.hpp | 6 ++
hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp | 10 +-
hotspot/src/cpu/ppc/vm/ppc.ad | 37 ++++++--
hotspot/src/cpu/ppc/vm/runtime_ppc.cpp | 12 ++-
hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 93 +++++++++++--------
hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 85 +++++++++++------
hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 15 ++-
hotspot/src/share/vm/utilities/elfFile.cpp | 2 +-
16 files changed, 298 insertions(+), 126 deletions(-)
diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp
index b0519a63b08..56b0b92db73 100644
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp
@@ -124,6 +124,7 @@ class Argument VALUE_OBJ_CLASS_SPEC {
}
};
+#if !defined(ABI_ELFv2)
// A ppc64 function descriptor.
struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC {
private:
@@ -161,6 +162,7 @@ struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC {
_env = (address) 0xbad;
}
};
+#endif
class Assembler : public AbstractAssembler {
protected:
@@ -1067,6 +1069,7 @@ class Assembler : public AbstractAssembler {
// Emit an address.
inline address emit_addr(const address addr = NULL);
+#if !defined(ABI_ELFv2)
// Emit a function descriptor with the specified entry point, TOC,
// and ENV. If the entry point is NULL, the descriptor will point
// just past the descriptor.
@@ -1074,6 +1077,7 @@ class Assembler : public AbstractAssembler {
inline address emit_fd(address entry = NULL,
address toc = (address) FunctionDescriptor::friend_toc,
address env = (address) FunctionDescriptor::friend_env);
+#endif
/////////////////////////////////////////////////////////////////////////////////////
// PPC instructions
diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp
index 200aaf11aed..d96d9204dbc 100644
--- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp
+++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp
@@ -55,6 +55,7 @@ inline address Assembler::emit_addr(const address addr) {
return start;
}
+#if !defined(ABI_ELFv2)
// Emit a function descriptor with the specified entry point, TOC, and
// ENV. If the entry point is NULL, the descriptor will point just
// past the descriptor.
@@ -73,6 +74,7 @@ inline address Assembler::emit_fd(address entry, address toc, address env) {
return (address)fd;
}
+#endif
// Issue an illegal instruction. 0 is guaranteed to be an illegal instruction.
inline void Assembler::illtrap() { Assembler::emit_int32(0); }
diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
index c9853c589cc..44c09d9c30a 100644
--- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
@@ -1136,7 +1136,9 @@ address CppInterpreterGenerator::generate_native_entry(void) {
// (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to
// F13_ARG13.
__ mr(R3_ARG1, R18_locals);
+#if !defined(ABI_ELFv2)
__ ld(signature_handler_fd, 0, signature_handler_fd);
+#endif
__ call_stub(signature_handler_fd);
// reload method
__ ld(R19_method, state_(_method));
@@ -1295,8 +1297,13 @@ address CppInterpreterGenerator::generate_native_entry(void) {
// native result acrosss the call. No oop is present
__ mr(R3_ARG1, R16_thread);
+#if defined(ABI_ELFv2)
+ __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
+ relocInfo::none);
+#else
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
relocInfo::none);
+#endif
__ bind(sync_check_done);
//=============================================================================
@@ -1413,7 +1420,7 @@ address CppInterpreterGenerator::generate_native_entry(void) {
// First, pop to caller's frame.
__ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2);
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
// Get the address of the exception handler.
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
R16_thread,
@@ -2545,7 +2552,7 @@ address CppInterpreterGenerator::generate_normal_entry(void) {
__ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1
// Find the address of the "catch_exception" stub.
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
R16_thread,
R4_ARG2);
diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
index 26321baeb89..b0a350252ad 100644
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
@@ -50,7 +50,7 @@
// [C_FRAME]
//
// C_FRAME:
- // 0 [ABI_112]
+ // 0 [ABI_REG_ARGS]
// 112 CARG_9: outgoing arg 9 (arg_1 ... arg_8 via gpr_3 ... gpr_{10})
// ...
// 40+M*8 CARG_M: outgoing arg M (M is the maximum of outgoing args taken over all call sites in the procedure)
@@ -77,7 +77,7 @@
// 32 reserved
// 40 space for TOC (=R2) register for next call
//
- // ABI_112:
+ // ABI_REG_ARGS:
// 0 [ABI_48]
// 48 CARG_1: spill slot for outgoing arg 1. used by next callee.
// ... ...
@@ -95,23 +95,25 @@
log_2_of_alignment_in_bits = 7
};
- // ABI_48:
- struct abi_48 {
+ // ABI_MINFRAME:
+ struct abi_minframe {
uint64_t callers_sp;
uint64_t cr; //_16
uint64_t lr;
+#if !defined(ABI_ELFv2)
uint64_t reserved1; //_16
uint64_t reserved2;
+#endif
uint64_t toc; //_16
// nothing to add here!
// aligned to frame::alignment_in_bytes (16)
};
enum {
- abi_48_size = sizeof(abi_48)
+ abi_minframe_size = sizeof(abi_minframe)
};
- struct abi_112 : abi_48 {
+ struct abi_reg_args : abi_minframe {
uint64_t carg_1;
uint64_t carg_2; //_16
uint64_t carg_3;
@@ -124,13 +126,13 @@
};
enum {
- abi_112_size = sizeof(abi_112)
+ abi_reg_args_size = sizeof(abi_reg_args)
};
#define _abi(_component) \
- (offset_of(frame::abi_112, _component))
+ (offset_of(frame::abi_reg_args, _component))
- struct abi_112_spill : abi_112 {
+ struct abi_reg_args_spill : abi_reg_args {
// additional spill slots
uint64_t spill_ret;
uint64_t spill_fret; //_16
@@ -138,11 +140,11 @@
};
enum {
- abi_112_spill_size = sizeof(abi_112_spill)
+ abi_reg_args_spill_size = sizeof(abi_reg_args_spill)
};
- #define _abi_112_spill(_component) \
- (offset_of(frame::abi_112_spill, _component))
+ #define _abi_reg_args_spill(_component) \
+ (offset_of(frame::abi_reg_args_spill, _component))
// non-volatile GPRs:
@@ -242,7 +244,7 @@
// [ENTRY_FRAME_LOCALS]
//
// PARENT_IJAVA_FRAME_ABI:
- // 0 [ABI_48]
+ // 0 [ABI_MINFRAME]
// top_frame_sp
// initial_caller_sp
//
@@ -258,7 +260,7 @@
// PARENT_IJAVA_FRAME_ABI
- struct parent_ijava_frame_abi : abi_48 {
+ struct parent_ijava_frame_abi : abi_minframe {
// SOE registers.
// C2i adapters spill their top-frame stack-pointer here.
uint64_t top_frame_sp; // carg_1
@@ -285,7 +287,7 @@
uint64_t carg_6_unused; //_16 carg_6
uint64_t carg_7_unused; // carg_7
// Use arg8 for storing frame_manager_lr. The size of
- // top_ijava_frame_abi must match abi_112.
+ // top_ijava_frame_abi must match abi_reg_args.
uint64_t frame_manager_lr; //_16 carg_8
// nothing to add here!
// aligned to frame::alignment_in_bytes (16)
@@ -395,8 +397,8 @@
intptr_t* fp() const { return _fp; }
// Accessors for ABIs
- inline abi_48* own_abi() const { return (abi_48*) _sp; }
- inline abi_48* callers_abi() const { return (abi_48*) _fp; }
+ inline abi_minframe* own_abi() const { return (abi_minframe*) _sp; }
+ inline abi_minframe* callers_abi() const { return (abi_minframe*) _fp; }
private:
diff --git a/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp
index 3a1389f413b..5d45d8bf82f 100644
--- a/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/interpreterRT_ppc.cpp
@@ -109,8 +109,10 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_object() {
}
void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
+#if !defined(ABI_ELFv2)
// Emit fd for current codebuffer. Needs patching!
__ emit_fd();
+#endif
// Generate code to handle arguments.
iterate(fingerprint);
@@ -127,11 +129,13 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin
// Implementation of SignatureHandlerLibrary
void SignatureHandlerLibrary::pd_set_handler(address handler) {
+#if !defined(ABI_ELFv2)
// patch fd here.
FunctionDescriptor* fd = (FunctionDescriptor*) handler;
fd->set_entry(handler + (int)sizeof(FunctionDescriptor));
assert(fd->toc() == (address)0xcafe, "need to adjust TOC here");
+#endif
}
diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
index 3cc1b7f07e9..03e1b1e7d54 100644
--- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
@@ -128,13 +128,13 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() {
const Register target_sp = R28_tmp8;
const FloatRegister floatSlot = F0;
- address entry = __ emit_fd();
+ address entry = __ function_entry();
__ save_LR_CR(R0);
__ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14));
// We use target_sp for storing arguments in the C frame.
__ mr(target_sp, R1_SP);
- __ push_frame_abi112_nonvolatiles(0, R11_scratch1);
+ __ push_frame_reg_args_nonvolatiles(0, R11_scratch1);
__ mr(arg_java, R3_ARG1);
@@ -474,7 +474,7 @@ address InterpreterGenerator::generate_abstract_entry(void) {
// Push a new C frame and save LR.
__ save_LR_CR(R0);
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
// This is not a leaf but we have a JavaFrameAnchor now and we will
// check (create) exceptions afterward so this is ok.
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
index dfe97adadb5..603e3ed2592 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
@@ -594,7 +594,13 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool
"can't identify emitted call");
} else {
// variant 1:
-
+#if defined(ABI_ELFv2)
+ nop();
+ calculate_address_from_global_toc(R12, dest, true, true, false);
+ mtctr(R12);
+ nop();
+ nop();
+#else
mr(R0, R11); // spill R11 -> R0.
// Load the destination address into CTR,
@@ -604,6 +610,7 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool
mtctr(R11);
mr(R11, R0); // spill R11 <- R0.
nop();
+#endif
// do the call/jump
if (link) {
@@ -912,16 +919,16 @@ void MacroAssembler::push_frame(unsigned int bytes, Register tmp) {
}
}
-// Push a frame of size `bytes' plus abi112 on top.
-void MacroAssembler::push_frame_abi112(unsigned int bytes, Register tmp) {
- push_frame(bytes + frame::abi_112_size, tmp);
+// Push a frame of size `bytes' plus abi_reg_args on top.
+void MacroAssembler::push_frame_reg_args(unsigned int bytes, Register tmp) {
+ push_frame(bytes + frame::abi_reg_args_size, tmp);
}
// Setup up a new C frame with a spill area for non-volatile GPRs and
// additional space for local variables.
-void MacroAssembler::push_frame_abi112_nonvolatiles(unsigned int bytes,
- Register tmp) {
- push_frame(bytes + frame::abi_112_size + frame::spill_nonvolatiles_size, tmp);
+void MacroAssembler::push_frame_reg_args_nonvolatiles(unsigned int bytes,
+ Register tmp) {
+ push_frame(bytes + frame::abi_reg_args_size + frame::spill_nonvolatiles_size, tmp);
}
// Pop current C frame.
@@ -929,6 +936,42 @@ void MacroAssembler::pop_frame() {
ld(R1_SP, _abi(callers_sp), R1_SP);
}
+#if defined(ABI_ELFv2)
+address MacroAssembler::branch_to(Register r_function_entry, bool and_link) {
+ // TODO(asmundak): make sure the caller uses R12 as function descriptor
+ // most of the times.
+ if (R12 != r_function_entry) {
+ mr(R12, r_function_entry);
+ }
+ mtctr(R12);
+ // Do a call or a branch.
+ if (and_link) {
+ bctrl();
+ } else {
+ bctr();
+ }
+ _last_calls_return_pc = pc();
+
+ return _last_calls_return_pc;
+}
+
+// Call a C function via a function descriptor and use full C
+// calling conventions. Updates and returns _last_calls_return_pc.
+address MacroAssembler::call_c(Register r_function_entry) {
+ return branch_to(r_function_entry, /*and_link=*/true);
+}
+
+// For tail calls: only branch, don't link, so callee returns to caller of this function.
+address MacroAssembler::call_c_and_return_to_caller(Register r_function_entry) {
+ return branch_to(r_function_entry, /*and_link=*/false);
+}
+
+address MacroAssembler::call_c(address function_entry, relocInfo::relocType rt) {
+ load_const(R12, function_entry, R0);
+ return branch_to(R12, /*and_link=*/true);
+}
+
+#else
// Generic version of a call to C function via a function descriptor
// with variable support for C calling conventions (TOC, ENV, etc.).
// Updates and returns _last_calls_return_pc.
@@ -1077,6 +1120,7 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd,
}
return _last_calls_return_pc;
}
+#endif
void MacroAssembler::call_VM_base(Register oop_result,
Register last_java_sp,
@@ -1091,8 +1135,11 @@ void MacroAssembler::call_VM_base(Register oop_result,
// ARG1 must hold thread address.
mr(R3_ARG1, R16_thread);
-
+#if defined(ABI_ELFv2)
+ address return_pc = call_c(entry_point, relocInfo::none);
+#else
address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none);
+#endif
reset_last_Java_frame();
@@ -1113,7 +1160,11 @@ void MacroAssembler::call_VM_base(Register oop_result,
void MacroAssembler::call_VM_leaf_base(address entry_point) {
BLOCK_COMMENT("call_VM_leaf {");
+#if defined(ABI_ELFv2)
+ call_c(entry_point, relocInfo::none);
+#else
call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none);
+#endif
BLOCK_COMMENT("} call_VM_leaf");
}
@@ -2227,7 +2278,7 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs
// VM call need frame to access(write) O register.
if (needs_frame) {
save_LR_CR(Rtmp1);
- push_frame_abi112(0, Rtmp2);
+ push_frame_reg_args(0, Rtmp2);
}
if (Rpre_val->is_volatile() && Robj == noreg) mr(R31, Rpre_val); // Save pre_val across C call if it was preloaded.
@@ -3006,13 +3057,13 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) {
mr(R0, tmp);
// kill tmp
save_LR_CR(tmp);
- push_frame_abi112(nbytes_save, tmp);
+ push_frame_reg_args(nbytes_save, tmp);
// restore tmp
mr(tmp, R0);
save_volatile_gprs(R1_SP, 112); // except R0
- // load FunctionDescriptor**
+ // load FunctionDescriptor** / entry_address *
load_const(tmp, fd);
- // load FunctionDescriptor*
+ // load FunctionDescriptor* / entry_address
ld(tmp, 0, tmp);
mr(R4_ARG2, oop);
load_const(R3_ARG1, (address)msg);
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
index e3ba572c67f..9b793ef1547 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
@@ -279,12 +279,12 @@ class MacroAssembler: public Assembler {
// Push a frame of size `bytes'. No abi space provided.
void push_frame(unsigned int bytes, Register tmp);
- // Push a frame of size `bytes' plus abi112 on top.
- void push_frame_abi112(unsigned int bytes, Register tmp);
+ // Push a frame of size `bytes' plus abi_reg_args on top.
+ void push_frame_reg_args(unsigned int bytes, Register tmp);
// Setup up a new C frame with a spill area for non-volatile GPRs and additional
// space for local variables
- void push_frame_abi112_nonvolatiles(unsigned int bytes, Register tmp);
+ void push_frame_reg_args_nonvolatiles(unsigned int bytes, Register tmp);
// pop current C frame
void pop_frame();
@@ -296,17 +296,31 @@ class MacroAssembler: public Assembler {
private:
address _last_calls_return_pc;
+#if defined(ABI_ELFv2)
+ // Generic version of a call to C function.
+ // Updates and returns _last_calls_return_pc.
+ address branch_to(Register function_entry, bool and_link);
+#else
// Generic version of a call to C function via a function descriptor
// with variable support for C calling conventions (TOC, ENV, etc.).
// updates and returns _last_calls_return_pc.
address branch_to(Register function_descriptor, bool and_link, bool save_toc_before_call,
bool restore_toc_after_call, bool load_toc_of_callee, bool load_env_of_callee);
+#endif
public:
// Get the pc where the last call will return to. returns _last_calls_return_pc.
inline address last_calls_return_pc();
+#if defined(ABI_ELFv2)
+ // Call a C function via a function descriptor and use full C
+ // calling conventions. Updates and returns _last_calls_return_pc.
+ address call_c(Register function_entry);
+ // For tail calls: only branch, don't link, so callee returns to caller of this function.
+ address call_c_and_return_to_caller(Register function_entry);
+ address call_c(address function_entry, relocInfo::relocType rt);
+#else
// Call a C function via a function descriptor and use full C
// calling conventions. Updates and returns _last_calls_return_pc.
address call_c(Register function_descriptor);
@@ -315,6 +329,7 @@ class MacroAssembler: public Assembler {
address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt);
address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt,
Register toc);
+#endif
protected:
@@ -649,6 +664,11 @@ class MacroAssembler: public Assembler {
void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line) {}
+ // Convenience method returning function entry. For the ELFv1 case
+ // creates function descriptor at the current address and returs
+ // the pointer to it. For the ELFv2 case returns the current address.
+ inline address function_entry();
+
#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
index 93f31a70f5e..bebfb4b6305 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
@@ -385,4 +385,10 @@ inline void MacroAssembler::trap_range_check_ge(Register a, int si16) {
twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16);
}
+#if defined(ABI_ELFv2)
+inline address MacroAssembler::function_entry() { return pc(); }
+#else
+inline address MacroAssembler::function_entry() { return emit_fd(); }
+#endif
+
#endif // CPU_PPC_VM_MACROASSEMBLER_PPC_INLINE_HPP
diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
index 6709c8ce680..26363754b09 100644
--- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp
@@ -453,11 +453,11 @@ void trace_method_handle_stub(const char* adaptername,
if (Verbose) {
tty->print_cr("Registers:");
- const int abi_offset = frame::abi_112_size / 8;
+ const int abi_offset = frame::abi_reg_args_size / 8;
for (int i = R3->encoding(); i <= R12->encoding(); i++) {
Register r = as_Register(i);
int count = i - R3->encoding();
- // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_112_size)).
+ // The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_reg_args_size)).
tty->print("%3s=" PTR_FORMAT, r->name(), saved_regs[abi_offset + count]);
if ((count + 1) % 4 == 0) {
tty->cr();
@@ -524,9 +524,9 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt
__ save_LR_CR(R0);
__ mr(R0, R1_SP); // saved_sp
assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0");
- // push_frame_abi112 only uses R0 if nbytes_save is wider than 16 bit
- __ push_frame_abi112(nbytes_save, R0);
- __ save_volatile_gprs(R1_SP, frame::abi_112_size); // Except R0.
+ // Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit.
+ __ push_frame_reg_args(nbytes_save, R0);
+ __ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0.
__ load_const(R3_ARG1, (address)adaptername);
__ mr(R4_ARG2, R23_method_handle);
diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad
index 6006c1acaf6..c2854e68e16 100644
--- a/hotspot/src/cpu/ppc/vm/ppc.ad
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad
@@ -1008,7 +1008,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() {
}
int MachCallRuntimeNode::ret_addr_offset() {
+#if defined(ABI_ELFv2)
+ return 28;
+#else
return 40;
+#endif
}
//=============================================================================
@@ -3674,6 +3678,10 @@ encode %{
MacroAssembler _masm(&cbuf);
const address start_pc = __ pc();
+#if defined(ABI_ELFv2)
+ address entry= !($meth$$method) ? NULL : (address)$meth$$method;
+ __ call_c(entry, relocInfo::runtime_call_type);
+#else
// The function we're going to call.
FunctionDescriptor fdtemp;
const FunctionDescriptor* fd = !($meth$$method) ? &fdtemp : (FunctionDescriptor*)$meth$$method;
@@ -3684,6 +3692,7 @@ encode %{
// Put entry, env, toc into the constant pool, this needs up to 3 constant
// pool entries; call_c_using_toc will optimize the call.
__ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc);
+#endif
// Check the ret_addr_offset.
assert(((MachCallRuntimeNode*)this)->ret_addr_offset() == __ last_calls_return_pc() - start_pc,
@@ -3699,20 +3708,25 @@ encode %{
__ mtctr($src$$Register);
%}
- // postalloc expand emitter for runtime leaf calls.
+ // Postalloc expand emitter for runtime leaf calls.
enc_class postalloc_expand_java_to_runtime_call(method meth, iRegLdst toc) %{
+ loadConLNodesTuple loadConLNodes_Entry;
+#if defined(ABI_ELFv2)
+ jlong entry_address = (jlong) this->entry_point();
+ assert(entry_address, "need address here");
+ loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address),
+ OptoReg::Name(R12_H_num), OptoReg::Name(R12_num));
+#else
// Get the struct that describes the function we are about to call.
FunctionDescriptor* fd = (FunctionDescriptor*) this->entry_point();
assert(fd, "need fd here");
+ jlong entry_address = (jlong) fd->entry();
// new nodes
- loadConLNodesTuple loadConLNodes_Entry;
loadConLNodesTuple loadConLNodes_Env;
loadConLNodesTuple loadConLNodes_Toc;
- MachNode *mtctr = NULL;
- MachCallLeafNode *call = NULL;
// Create nodes and operands for loading the entry point.
- loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->entry()),
+ loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address),
OptoReg::Name(R12_H_num), OptoReg::Name(R12_num));
@@ -3733,8 +3747,9 @@ encode %{
// Create nodes and operands for loading the Toc point.
loadConLNodes_Toc = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->toc()),
OptoReg::Name(R2_H_num), OptoReg::Name(R2_num));
+#endif // ABI_ELFv2
// mtctr node
- mtctr = new (C) CallLeafDirect_mtctrNode();
+ MachNode *mtctr = new (C) CallLeafDirect_mtctrNode();
assert(loadConLNodes_Entry._last != NULL, "entry must exist");
mtctr->add_req(0, loadConLNodes_Entry._last);
@@ -3743,10 +3758,10 @@ encode %{
mtctr->_opnds[1] = new (C) iRegLdstOper();
// call node
- call = new (C) CallLeafDirectNode();
+ MachCallLeafNode *call = new (C) CallLeafDirectNode();
call->_opnds[0] = _opnds[0];
- call->_opnds[1] = new (C) methodOper((intptr_t) fd->entry()); // may get set later
+ call->_opnds[1] = new (C) methodOper((intptr_t) entry_address); // May get set later.
// Make the new call node look like the old one.
call->_name = _name;
@@ -3773,8 +3788,10 @@ encode %{
// These must be reqired edges, as the registers are live up to
// the call. Else the constants are handled as kills.
call->add_req(mtctr);
+#if !defined(ABI_ELFv2)
call->add_req(loadConLNodes_Env._last);
call->add_req(loadConLNodes_Toc._last);
+#endif
// ...as well as prec
for (uint i = req(); i < len(); ++i) {
@@ -3787,10 +3804,12 @@ encode %{
// Insert the new nodes.
if (loadConLNodes_Entry._large_hi) nodes->push(loadConLNodes_Entry._large_hi);
if (loadConLNodes_Entry._last) nodes->push(loadConLNodes_Entry._last);
+#if !defined(ABI_ELFv2)
if (loadConLNodes_Env._large_hi) nodes->push(loadConLNodes_Env._large_hi);
if (loadConLNodes_Env._last) nodes->push(loadConLNodes_Env._last);
if (loadConLNodes_Toc._large_hi) nodes->push(loadConLNodes_Toc._large_hi);
if (loadConLNodes_Toc._last) nodes->push(loadConLNodes_Toc._last);
+#endif
nodes->push(mtctr);
nodes->push(call);
%}
@@ -3837,7 +3856,7 @@ frame %{
// out_preserve_stack_slots for calls to C. Supports the var-args
// backing area for register parms.
//
- varargs_C_out_slots_killed(((frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size));
+ varargs_C_out_slots_killed(((frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size));
// The after-PROLOG location of the return address. Location of
// return address specifies a type (REG or STACK) and a number
diff --git a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp
index bc3432bb1e3..0e5898381c2 100644
--- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp
@@ -87,7 +87,7 @@ void OptoRuntime::generate_exception_blob() {
address start = __ pc();
- int frame_size_in_bytes = frame::abi_112_size;
+ int frame_size_in_bytes = frame::abi_reg_args_size;
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
// Exception pc is 'return address' for stack walker.
@@ -99,7 +99,7 @@ void OptoRuntime::generate_exception_blob() {
// Save callee-saved registers.
// Push a C frame for the exception blob. It is needed for the C call later on.
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
// This call does all the hard work. It checks if an exception handler
// exists in the method.
@@ -109,8 +109,12 @@ void OptoRuntime::generate_exception_blob() {
__ set_last_Java_frame(/*sp=*/R1_SP, noreg);
__ mr(R3_ARG1, R16_thread);
+#if defined(ABI_ELFv2)
+ __ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none);
+#else
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C),
relocInfo::none);
+#endif
address calls_return_pc = __ last_calls_return_pc();
# ifdef ASSERT
__ cmpdi(CCR0, R3_RET, 0);
@@ -162,7 +166,11 @@ void OptoRuntime::generate_exception_blob() {
__ bind(mh_callsite);
__ mr(R31, R3_RET); // Save branch address.
__ mr(R3_ARG1, R16_thread);
+#if defined(ABI_ELFv2)
+ __ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none);
+#else
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none);
+#endif
// Returns unextended_sp in R3_RET.
__ mtctr(R31); // Move address of exception handler to SR_CTR.
diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
index 2d9b4900bce..323bdf46771 100644
--- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
@@ -67,7 +67,7 @@ class RegisterSaver {
return_pc_is_thread_saved_exception_pc
};
- static OopMap* push_frame_abi112_and_save_live_registers(MacroAssembler* masm,
+ static OopMap* push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
int* out_frame_size_in_bytes,
bool generate_oop_map,
int return_pc_adjustment,
@@ -200,12 +200,12 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveRegs[] = {
RegisterSaver_LiveIntReg( R30 ), // r30 must be the last register
};
-OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* masm,
+OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
int* out_frame_size_in_bytes,
bool generate_oop_map,
int return_pc_adjustment,
ReturnPCLocation return_pc_location) {
- // Push an abi112-frame and store all registers which may be live.
+ // Push an abi_reg_args-frame and store all registers which may be live.
// If requested, create an OopMap: Record volatile registers as
// callee-save values in an OopMap so their save locations will be
// propagated to the RegisterMap of the caller frame during
@@ -221,7 +221,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
sizeof(RegisterSaver::LiveRegType);
const int register_save_size = regstosave_num * reg_size;
const int frame_size_in_bytes = round_to(register_save_size, frame::alignment_in_bytes)
- + frame::abi_112_size;
+ + frame::abi_reg_args_size;
*out_frame_size_in_bytes = frame_size_in_bytes;
const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
const int register_save_offset = frame_size_in_bytes - register_save_size;
@@ -229,7 +229,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
// OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words.
OopMap* map = generate_oop_map ? new OopMap(frame_size_in_slots, 0) : NULL;
- BLOCK_COMMENT("push_frame_abi112_and_save_live_registers {");
+ BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {");
// Save r30 in the last slot of the not yet pushed frame so that we
// can use it as scratch reg.
@@ -294,7 +294,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
offset += reg_size;
}
- BLOCK_COMMENT("} push_frame_abi112_and_save_live_registers");
+ BLOCK_COMMENT("} push_frame_reg_args_and_save_live_registers");
// And we're done.
return map;
@@ -699,15 +699,19 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
int i;
VMReg reg;
- // Leave room for C-compatible ABI_112.
- int stk = (frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size;
+ // Leave room for C-compatible ABI_REG_ARGS.
+ int stk = (frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size;
int arg = 0;
int freg = 0;
// Avoid passing C arguments in the wrong stack slots.
+#if defined(ABI_ELFv2)
+ assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 96,
+ "passing C arguments in wrong stack slots");
+#else
assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 112,
"passing C arguments in wrong stack slots");
-
+#endif
// We fill-out regs AND regs2 if an argument must be passed in a
// register AND in a stack slot. If regs2 is NULL in such a
// situation, we bail-out with a fatal error.
@@ -1504,7 +1508,11 @@ static void check_needs_gc_for_critical_native(MacroAssembler* masm,
__ block_comment("block_for_jni_critical");
address entry_point = CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical);
+#if defined(ABI_ELFv2)
+ __ call_c(entry_point, relocInfo::runtime_call_type);
+#else
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::runtime_call_type);
+#endif
address start = __ pc() - __ offset(),
calls_return_pc = __ last_calls_return_pc();
oop_maps->add_gc_map(calls_return_pc - start, map);
@@ -1877,7 +1885,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// Layout of the native wrapper frame:
// (stack grows upwards, memory grows downwards)
//
- // NW [ABI_112] <-- 1) R1_SP
+ // NW [ABI_REG_ARGS] <-- 1) R1_SP
// [outgoing arguments] <-- 2) R1_SP + out_arg_slot_offset
// [oopHandle area] <-- 3) R1_SP + oop_handle_offset (save area for critical natives)
// klass <-- 4) R1_SP + klass_offset
@@ -2211,8 +2219,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// slow case of monitor enter. Inline a special case of call_VM that
// disallows any pending_exception.
- // Save argument registers and leave room for C-compatible ABI_112.
- int frame_size = frame::abi_112_size +
+ // Save argument registers and leave room for C-compatible ABI_REG_ARGS.
+ int frame_size = frame::abi_reg_args_size +
round_to(total_c_args * wordSize, frame::alignment_in_bytes);
__ mr(R11_scratch1, R1_SP);
RegisterSaver::push_frame_and_save_argument_registers(masm, R12_scratch2, frame_size, total_c_args, out_regs, out_regs2);
@@ -2250,9 +2258,12 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
// The JNI call
// --------------------------------------------------------------------------
-
+#if defined(ABI_ELFv2)
+ __ call_c(native_func, relocInfo::runtime_call_type);
+#else
FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func;
__ call_c(fd_native_method, relocInfo::runtime_call_type);
+#endif
// Now, we are back from the native code.
@@ -2724,7 +2735,7 @@ void SharedRuntime::generate_deopt_blob() {
OopMapSet *oop_maps = new OopMapSet();
// size of ABI112 plus spill slots for R3_RET and F1_RET.
- const int frame_size_in_bytes = frame::abi_112_spill_size;
+ const int frame_size_in_bytes = frame::abi_reg_args_spill_size;
const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
int first_frame_size_in_bytes = 0; // frame size of "unpack frame" for call to fetch_unroll_info.
@@ -2757,11 +2768,11 @@ void SharedRuntime::generate_deopt_blob() {
// Push the "unpack frame"
// Save everything in sight.
- map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
- &first_frame_size_in_bytes,
- /*generate_oop_map=*/ true,
- return_pc_adjustment_no_exception,
- RegisterSaver::return_pc_is_lr);
+ map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &first_frame_size_in_bytes,
+ /*generate_oop_map=*/ true,
+ return_pc_adjustment_no_exception,
+ RegisterSaver::return_pc_is_lr);
assert(map != NULL, "OopMap must have been created");
__ li(exec_mode_reg, Deoptimization::Unpack_deopt);
@@ -2787,11 +2798,11 @@ void SharedRuntime::generate_deopt_blob() {
// Push the "unpack frame".
// Save everything in sight.
assert(R4 == R4_ARG2, "exception pc must be in r4");
- RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
- &first_frame_size_in_bytes,
- /*generate_oop_map=*/ false,
- return_pc_adjustment_exception,
- RegisterSaver::return_pc_is_r4);
+ RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &first_frame_size_in_bytes,
+ /*generate_oop_map=*/ false,
+ return_pc_adjustment_exception,
+ RegisterSaver::return_pc_is_r4);
// Deopt during an exception. Save exec mode for unpack_frames.
__ li(exec_mode_reg, Deoptimization::Unpack_exception);
@@ -2876,8 +2887,8 @@ void SharedRuntime::generate_deopt_blob() {
// ...).
// Spill live volatile registers since we'll do a call.
- __ std( R3_RET, _abi_112_spill(spill_ret), R1_SP);
- __ stfd(F1_RET, _abi_112_spill(spill_fret), R1_SP);
+ __ std( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP);
+ __ stfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP);
// Let the unpacker layout information in the skeletal frames just
// allocated.
@@ -2889,8 +2900,8 @@ void SharedRuntime::generate_deopt_blob() {
__ reset_last_Java_frame();
// Restore the volatiles saved above.
- __ ld( R3_RET, _abi_112_spill(spill_ret), R1_SP);
- __ lfd(F1_RET, _abi_112_spill(spill_fret), R1_SP);
+ __ ld( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP);
+ __ lfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP);
// Pop the unpack frame.
__ pop_frame();
@@ -2930,7 +2941,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
Register unc_trap_reg = R23_tmp3;
OopMapSet* oop_maps = new OopMapSet();
- int frame_size_in_bytes = frame::abi_112_size;
+ int frame_size_in_bytes = frame::abi_reg_args_size;
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
// stack: (deoptee, optional i2c, caller_of_deoptee, ...).
@@ -2943,7 +2954,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
__ save_LR_CR(R11_scratch1);
// Push an "uncommon_trap" frame.
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
// stack: (unpack frame, deoptee, optional i2c, caller_of_deoptee, ...).
@@ -2996,7 +3007,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// interpreter frames just created.
// Push a simple "unpack frame" here.
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
// stack: (unpack frame, skeletal interpreter frame, ..., optional
// skeletal interpreter frame, optional c2i, caller of deoptee,
@@ -3064,11 +3075,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
}
// Save registers, fpu state, and flags.
- map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
- &frame_size_in_bytes,
- /*generate_oop_map=*/ true,
- /*return_pc_adjustment=*/0,
- return_pc_location);
+ map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &frame_size_in_bytes,
+ /*generate_oop_map=*/ true,
+ /*return_pc_adjustment=*/0,
+ return_pc_location);
// The following is basically a call_VM. However, we need the precise
// address of the call in order to generate an oopmap. Hence, we do all the
@@ -3151,11 +3162,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
address start = __ pc();
- map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
- &frame_size_in_bytes,
- /*generate_oop_map*/ true,
- /*return_pc_adjustment*/ 0,
- RegisterSaver::return_pc_is_lr);
+ map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
+ &frame_size_in_bytes,
+ /*generate_oop_map*/ true,
+ /*return_pc_adjustment*/ 0,
+ RegisterSaver::return_pc_is_lr);
// Use noreg as last_Java_pc, the return pc will be reconstructed
// from the physical frame.
diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
index 1cd4d295925..96c3ae94648 100644
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
@@ -79,11 +79,11 @@ class StubGenerator: public StubCodeGenerator {
StubCodeMark mark(this, "StubRoutines", "call_stub");
- address start = __ emit_fd();
+ address start = __ function_entry();
// some sanity checks
- assert((sizeof(frame::abi_48) % 16) == 0, "unaligned");
- assert((sizeof(frame::abi_112) % 16) == 0, "unaligned");
+ assert((sizeof(frame::abi_minframe) % 16) == 0, "unaligned");
+ assert((sizeof(frame::abi_reg_args) % 16) == 0, "unaligned");
assert((sizeof(frame::spill_nonvolatiles) % 16) == 0, "unaligned");
assert((sizeof(frame::parent_ijava_frame_abi) % 16) == 0, "unaligned");
assert((sizeof(frame::entry_frame_locals) % 16) == 0, "unaligned");
@@ -444,7 +444,7 @@ class StubGenerator: public StubCodeGenerator {
// Save LR/CR and copy exception pc (LR) into R4_ARG2.
__ save_LR_CR(R4_ARG2);
- __ push_frame_abi112(0, R0);
+ __ push_frame_reg_args(0, R0);
// Find exception handler.
__ call_VM_leaf(CAST_FROM_FN_PTR(address,
SharedRuntime::exception_handler_for_return_address),
@@ -519,7 +519,7 @@ class StubGenerator: public StubCodeGenerator {
MacroAssembler* masm = new MacroAssembler(&code);
OopMapSet* oop_maps = new OopMapSet();
- int frame_size_in_bytes = frame::abi_112_size;
+ int frame_size_in_bytes = frame::abi_reg_args_size;
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
StubCodeMark mark(this, "StubRoutines", "throw_exception");
@@ -529,7 +529,7 @@ class StubGenerator: public StubCodeGenerator {
__ save_LR_CR(R11_scratch1);
// Push a frame.
- __ push_frame_abi112(0, R11_scratch1);
+ __ push_frame_reg_args(0, R11_scratch1);
address frame_complete_pc = __ pc();
@@ -551,8 +551,11 @@ class StubGenerator: public StubCodeGenerator {
if (arg2 != noreg) {
__ mr(R5_ARG3, arg2);
}
- __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry),
- relocInfo::none);
+#if defined(ABI_ELFv2)
+ __ call_c(runtime_entry, relocInfo::none);
+#else
+ __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none);
+#endif
// Set an oopmap for the call site.
oop_maps->add_gc_map((int)(gc_map_pc - start), map);
@@ -614,7 +617,7 @@ class StubGenerator: public StubCodeGenerator {
// With G1, don't generate the call if we statically know that the target in uninitialized
if (!dest_uninitialized) {
const int spill_slots = 4 * wordSize;
- const int frame_size = frame::abi_112_size + spill_slots;
+ const int frame_size = frame::abi_reg_args_size + spill_slots;
Label filtered;
// Is marking active?
@@ -628,7 +631,7 @@ class StubGenerator: public StubCodeGenerator {
__ beq(CCR0, filtered);
__ save_LR_CR(R0);
- __ push_frame_abi112(spill_slots, R0);
+ __ push_frame_reg_args(spill_slots, R0);
__ std(from, frame_size - 1 * wordSize, R1_SP);
__ std(to, frame_size - 2 * wordSize, R1_SP);
__ std(count, frame_size - 3 * wordSize, R1_SP);
@@ -672,7 +675,7 @@ class StubGenerator: public StubCodeGenerator {
if (branchToEnd) {
__ save_LR_CR(R0);
// We need this frame only to spill LR.
- __ push_frame_abi112(0, R0);
+ __ push_frame_reg_args(0, R0);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count);
__ pop_frame();
__ restore_LR_CR(R0);
@@ -742,7 +745,7 @@ class StubGenerator: public StubCodeGenerator {
StubCodeMark mark(this, "StubRoutines", "zero_words_aligned8");
// Implemented as in ClearArray.
- address start = __ emit_fd();
+ address start = __ function_entry();
Register base_ptr_reg = R3_ARG1; // tohw (needs to be 8b aligned)
Register cnt_dwords_reg = R4_ARG2; // count (in dwords)
@@ -820,7 +823,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_handler_for_unsafe_access() {
StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access");
- address start = __ emit_fd();
+ address start = __ function_entry();
__ unimplemented("StubRoutines::handler_for_unsafe_access", 93);
return start;
}
@@ -861,7 +864,7 @@ class StubGenerator: public StubCodeGenerator {
// to read from the safepoint polling page.
address generate_load_from_poll() {
StubCodeMark mark(this, "StubRoutines", "generate_load_from_poll");
- address start = __ emit_fd();
+ address start = __ function_entry();
__ unimplemented("StubRoutines::verify_oop", 95); // TODO PPC port
return start;
}
@@ -885,7 +888,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_fill(BasicType t, bool aligned, const char* name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
const Register to = R3_ARG1; // source array address
const Register value = R4_ARG2; // fill value
@@ -1123,7 +1126,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_disjoint_byte_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
Register tmp1 = R6_ARG4;
Register tmp2 = R7_ARG5;
@@ -1254,15 +1257,21 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_conjoint_byte_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
Register tmp1 = R6_ARG4;
Register tmp2 = R7_ARG5;
Register tmp3 = R8_ARG6;
+#if defined(ABI_ELFv2)
+ address nooverlap_target = aligned ?
+ StubRoutines::arrayof_jbyte_disjoint_arraycopy() :
+ StubRoutines::jbyte_disjoint_arraycopy();
+#else
address nooverlap_target = aligned ?
((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() :
((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry();
+#endif
array_overlap_test(nooverlap_target, 0);
// Do reverse copy. We assume the case of actual overlap is rare enough
@@ -1345,7 +1354,7 @@ class StubGenerator: public StubCodeGenerator {
Register tmp3 = R8_ARG6;
Register tmp4 = R9_ARG7;
- address start = __ emit_fd();
+ address start = __ function_entry();
Label l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8;
// don't try anything fancy if arrays don't have many elements
@@ -1474,15 +1483,21 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_conjoint_short_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
Register tmp1 = R6_ARG4;
Register tmp2 = R7_ARG5;
Register tmp3 = R8_ARG6;
+#if defined(ABI_ELFv2)
+ address nooverlap_target = aligned ?
+ StubRoutines::arrayof_jshort_disjoint_arraycopy() :
+ StubRoutines::jshort_disjoint_arraycopy();
+#else
address nooverlap_target = aligned ?
((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() :
((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry();
+#endif
array_overlap_test(nooverlap_target, 1);
@@ -1597,7 +1612,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_disjoint_int_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
generate_disjoint_int_copy_core(aligned);
__ blr();
return start;
@@ -1681,11 +1696,17 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_conjoint_int_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
+#if defined(ABI_ELFv2)
+ address nooverlap_target = aligned ?
+ StubRoutines::arrayof_jint_disjoint_arraycopy() :
+ StubRoutines::jint_disjoint_arraycopy();
+#else
address nooverlap_target = aligned ?
((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() :
((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry();
+#endif
array_overlap_test(nooverlap_target, 2);
@@ -1767,7 +1788,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_disjoint_long_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
generate_disjoint_long_copy_core(aligned);
__ blr();
@@ -1849,11 +1870,17 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_conjoint_long_copy(bool aligned, const char * name) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
+#if defined(ABI_ELFv2)
+ address nooverlap_target = aligned ?
+ StubRoutines::arrayof_jlong_disjoint_arraycopy() :
+ StubRoutines::jlong_disjoint_arraycopy();
+#else
address nooverlap_target = aligned ?
((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() :
((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry();
+#endif
array_overlap_test(nooverlap_target, 3);
generate_conjoint_long_copy_core(aligned);
@@ -1875,11 +1902,17 @@ class StubGenerator: public StubCodeGenerator {
address generate_conjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
+#if defined(ABI_ELFv2)
+ address nooverlap_target = aligned ?
+ StubRoutines::arrayof_oop_disjoint_arraycopy() :
+ StubRoutines::oop_disjoint_arraycopy();
+#else
address nooverlap_target = aligned ?
((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() :
((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry();
+#endif
gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7);
@@ -1910,7 +1943,7 @@ class StubGenerator: public StubCodeGenerator {
//
address generate_disjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) {
StubCodeMark mark(this, "StubRoutines", name);
- address start = __ emit_fd();
+ address start = __ function_entry();
gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7);
@@ -1991,7 +2024,7 @@ class StubGenerator: public StubCodeGenerator {
StubCodeMark mark(this, "StubRoutines", name);
// Entry point, pc or function descriptor.
- *entry = __ emit_fd();
+ *entry = __ function_entry();
// Load *adr into R4_ARG2, may fault.
*fault_pc = __ pc();
diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
index a732c7bfc80..567a5d0d3f6 100644
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp
@@ -24,7 +24,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_ppc.inline.hpp"
+#include "asm/assembler.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "compiler/disassembler.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
@@ -168,7 +169,7 @@ void VM_Version::determine_section_size() {
uint32_t *code = (uint32_t *)a->pc();
// Emit code.
- void (*test1)() = (void(*)())(void *)a->emit_fd();
+ void (*test1)() = (void(*)())(void *)a->function_entry();
Label l1;
@@ -242,7 +243,7 @@ void VM_Version::determine_section_size() {
a->blr();
// Emit code.
- void (*test2)() = (void(*)())(void *)a->emit_fd();
+ void (*test2)() = (void(*)())(void *)a->function_entry();
// uint32_t *code = (uint32_t *)a->pc();
Label l2;
@@ -383,8 +384,12 @@ void VM_Version::determine_section_size() {
#endif // COMPILER2
void VM_Version::determine_features() {
+#if defined(ABI_ELFv2)
+ const int code_size = (num_features+1+2*7)*BytesPerInstWord; // TODO(asmundak): calculation is incorrect.
+#else
// 7 InstWords for each call (function descriptor + blr instruction).
const int code_size = (num_features+1+2*7)*BytesPerInstWord;
+#endif
int features = 0;
// create test area
@@ -398,7 +403,7 @@ void VM_Version::determine_features() {
MacroAssembler* a = new MacroAssembler(&cb);
// Emit code.
- void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->emit_fd();
+ void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry();
uint32_t *code = (uint32_t *)a->pc();
// Don't use R0 in ldarx.
// Keep R3_ARG1 unmodified, it contains &field (see below).
@@ -415,7 +420,7 @@ void VM_Version::determine_features() {
a->blr();
// Emit function to set one cache line to zero. Emit function descriptor and get pointer to it.
- void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->emit_fd();
+ void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry();
a->dcbz(R3_ARG1); // R3_ARG1 = addr
a->blr();
diff --git a/hotspot/src/share/vm/utilities/elfFile.cpp b/hotspot/src/share/vm/utilities/elfFile.cpp
index 371a036406c..3d895956315 100644
--- a/hotspot/src/share/vm/utilities/elfFile.cpp
+++ b/hotspot/src/share/vm/utilities/elfFile.cpp
@@ -140,7 +140,7 @@ bool ElfFile::load_tables() {
}
}
-#if defined(PPC64)
+#if defined(PPC64) && !defined(ABI_ELFv2)
// Now read the .opd section wich contains the PPC64 function descriptor table.
// The .opd section is only available on PPC64 (see for example:
// http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)
From 87b278c44ca338bebc8b89ea29ce8b17116fd0a0 Mon Sep 17 00:00:00 2001
From: Volker Simonis
Date: Thu, 6 Mar 2014 14:35:26 +0100
Subject: [PATCH 038/116] 8036777: AIX: Adapt implementation after '6546236:
Thread interrupt() of Thread.sleep() can be lost on Solaris.'
Reviewed-by: kvn
---
hotspot/src/os/aix/vm/os_aix.cpp | 156 +-----------------------
hotspot/src/os/aix/vm/os_aix.inline.hpp | 6 +
2 files changed, 10 insertions(+), 152 deletions(-)
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index ba6b8d494c6..33385e7a09a 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -1135,15 +1135,10 @@ jlong os::javaTimeNanos() {
}
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
- {
- // gettimeofday - based on time in seconds since the Epoch thus does not wrap
- info_ptr->max_value = ALL_64_BITS;
-
- // gettimeofday is a real time clock so it skips
- info_ptr->may_skip_backward = true;
- info_ptr->may_skip_forward = true;
- }
-
+ info_ptr->max_value = ALL_64_BITS;
+ // mread_real_time() is monotonic (see 'os::javaTimeNanos()')
+ info_ptr->may_skip_backward = false;
+ info_ptr->may_skip_forward = false;
info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
}
@@ -2799,105 +2794,6 @@ size_t os::read(int fd, void *buf, unsigned int nBytes) {
return ::read(fd, buf, nBytes);
}
-#define NANOSECS_PER_MILLISEC 1000000
-
-int os::sleep(Thread* thread, jlong millis, bool interruptible) {
- assert(thread == Thread::current(), "thread consistency check");
-
- // Prevent nasty overflow in deadline calculation
- // by handling long sleeps similar to solaris or windows.
- const jlong limit = INT_MAX;
- int result;
- while (millis > limit) {
- if ((result = os::sleep(thread, limit, interruptible)) != OS_OK) {
- return result;
- }
- millis -= limit;
- }
-
- ParkEvent * const slp = thread->_SleepEvent;
- slp->reset();
- OrderAccess::fence();
-
- if (interruptible) {
- jlong prevtime = javaTimeNanos();
-
- // Prevent precision loss and too long sleeps
- jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC;
-
- for (;;) {
- if (os::is_interrupted(thread, true)) {
- return OS_INTRPT;
- }
-
- jlong newtime = javaTimeNanos();
-
- assert(newtime >= prevtime, "time moving backwards");
- // Doing prevtime and newtime in microseconds doesn't help precision,
- // and trying to round up to avoid lost milliseconds can result in a
- // too-short delay.
- millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
-
- if (millis <= 0) {
- return OS_OK;
- }
-
- // Stop sleeping if we passed the deadline
- if (newtime >= deadline) {
- return OS_OK;
- }
-
- prevtime = newtime;
-
- {
- assert(thread->is_Java_thread(), "sanity check");
- JavaThread *jt = (JavaThread *) thread;
- ThreadBlockInVM tbivm(jt);
- OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
-
- jt->set_suspend_equivalent();
-
- slp->park(millis);
-
- // were we externally suspended while we were waiting?
- jt->check_and_wait_while_suspended();
- }
- }
- } else {
- OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
- jlong prevtime = javaTimeNanos();
-
- // Prevent precision loss and too long sleeps
- jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC;
-
- for (;;) {
- // It'd be nice to avoid the back-to-back javaTimeNanos() calls on
- // the 1st iteration ...
- jlong newtime = javaTimeNanos();
-
- if (newtime - prevtime < 0) {
- // time moving backwards, should only happen if no monotonic clock
- // not a guarantee() because JVM should not abort on kernel/glibc bugs
- // - HS14 Commented out as not implemented.
- // - TODO Maybe we should implement it?
- //assert(!Aix::supports_monotonic_clock(), "time moving backwards");
- } else {
- millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
- }
-
- if (millis <= 0) break;
-
- if (newtime >= deadline) {
- break;
- }
-
- prevtime = newtime;
- slp->park(millis);
- }
- return OS_OK;
- }
-}
-
void os::naked_short_sleep(jlong ms) {
struct timespec req;
@@ -3246,50 +3142,6 @@ static void do_resume(OSThread* osthread) {
guarantee(osthread->sr.is_running(), "Must be running!");
}
-////////////////////////////////////////////////////////////////////////////////
-// interrupt support
-
-void os::interrupt(Thread* thread) {
- assert(Thread::current() == thread || Threads_lock->owned_by_self(),
- "possibility of dangling Thread pointer");
-
- OSThread* osthread = thread->osthread();
-
- if (!osthread->interrupted()) {
- osthread->set_interrupted(true);
- // More than one thread can get here with the same value of osthread,
- // resulting in multiple notifications. We do, however, want the store
- // to interrupted() to be visible to other threads before we execute unpark().
- OrderAccess::fence();
- ParkEvent * const slp = thread->_SleepEvent;
- if (slp != NULL) slp->unpark();
- }
-
- // For JSR166. Unpark even if interrupt status already was set
- if (thread->is_Java_thread())
- ((JavaThread*)thread)->parker()->unpark();
-
- ParkEvent * ev = thread->_ParkEvent;
- if (ev != NULL) ev->unpark();
-
-}
-
-bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
- assert(Thread::current() == thread || Threads_lock->owned_by_self(),
- "possibility of dangling Thread pointer");
-
- OSThread* osthread = thread->osthread();
-
- bool interrupted = osthread->interrupted();
-
- if (interrupted && clear_interrupted) {
- osthread->set_interrupted(false);
- // consider thread->_SleepEvent->reset() ... optional optimization
- }
-
- return interrupted;
-}
-
///////////////////////////////////////////////////////////////////////////////////
// signal handling (except suspend/resume)
diff --git a/hotspot/src/os/aix/vm/os_aix.inline.hpp b/hotspot/src/os/aix/vm/os_aix.inline.hpp
index ff9c7a7aa3e..4a648559f52 100644
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp
+++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp
@@ -283,4 +283,10 @@ inline int os::set_sock_opt(int fd, int level, int optname,
const char* optval, socklen_t optlen) {
return ::setsockopt(fd, level, optname, optval, optlen);
}
+
+inline bool os::supports_monotonic_clock() {
+ // mread_real_time() is monotonic on AIX (see os::javaTimeNanos() comments)
+ return true;
+}
+
#endif // OS_AIX_VM_OS_AIX_INLINE_HPP
From af27057b263d8954ada8a03b5f715f5071794e8d Mon Sep 17 00:00:00 2001
From: Paul Govereau
Date: Thu, 6 Mar 2014 13:50:12 -0500
Subject: [PATCH 039/116] 8034091: There is no records in LineNumberTable
attribute for ternary operator ?: splitted to several lines
Reviewed-by: jjg
---
.../classes/com/sun/tools/javac/jvm/Gen.java | 2 +
.../ConditionalLineNumberTest.java | 80 +++++++++++++++++++
2 files changed, 82 insertions(+)
create mode 100644 langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
index 0f2cbcf1ed7..e1bda1c736d 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
@@ -1910,6 +1910,7 @@ public class Gen extends JCTree.Visitor {
if (!c.isFalse()) {
code.resolve(c.trueJumps);
int startpc = genCrt ? code.curCP() : 0;
+ code.statBegin(tree.truepart.pos);
genExpr(tree.truepart, pt).load();
code.state.forceStackTop(tree.type);
if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
@@ -1919,6 +1920,7 @@ public class Gen extends JCTree.Visitor {
if (elseChain != null) {
code.resolve(elseChain);
int startpc = genCrt ? code.curCP() : 0;
+ code.statBegin(tree.falsepart.pos);
genExpr(tree.falsepart, pt).load();
code.state.forceStackTop(tree.type);
if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
diff --git a/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java b/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java
new file mode 100644
index 00000000000..a1af968e806
--- /dev/null
+++ b/langtools/test/tools/javac/linenumbers/ConditionalLineNumberTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8034091
+ * @summary Add LineNumberTable attributes for conditional operator (?:) split across several lines.
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.LineNumberTable_attribute;
+import com.sun.tools.classfile.LineNumberTable_attribute.Entry;
+
+import java.io.File;
+import java.io.IOException;
+
+public class ConditionalLineNumberTest {
+ public static void main(String[] args) throws Exception {
+ // check that we have 5 consecutive entries for method()
+ Entry[] lines = findEntries();
+ if (lines == null || lines.length != 5)
+ throw new Exception("conditional line number table incorrect");
+
+ int current = lines[0].line_number;
+ for (Entry e : lines) {
+ if (e.line_number != current)
+ throw new Exception("conditional line number table incorrect");
+ current++;
+ }
+ }
+
+ static Entry[] findEntries() throws IOException, ConstantPoolException {
+ ClassFile self = ClassFile.read(ConditionalLineNumberTest.class.getResourceAsStream("ConditionalLineNumberTest.class"));
+ for (Method m : self.methods) {
+ if ("method".equals(m.getName(self.constant_pool))) {
+ Code_attribute code_attribute = (Code_attribute)m.attributes.get(Attribute.Code);
+ for (Attribute at : code_attribute.attributes) {
+ if (Attribute.LineNumberTable.equals(at.getName(self.constant_pool))) {
+ return ((LineNumberTable_attribute)at).line_number_table;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ // This method should get one LineNumberTable entry per line
+ // in the method body.
+ public static String method(int field) {
+ String s = field % 2 == 0 ?
+ (field == 0 ? "false"
+ : "true" + field) : //Breakpoint
+ "false" + field; //Breakpoint
+ return s;
+ }
+}
From e8bc971d1961bdad3cda137be28da6905c6faa49 Mon Sep 17 00:00:00 2001
From: Albert Noll
Date: Fri, 7 Mar 2014 07:42:40 +0100
Subject: [PATCH 040/116] 8029799: vm/mlvm/anonloader/stress/oome prints
warning: CodeHeap: # of free blocks > 10000
Double CodeCacheSegmentSize from 64 byte to 128 bytes if tiered compilation is enabled
Reviewed-by: kvn, twisti
---
hotspot/src/share/vm/code/codeCache.cpp | 50 ++--
hotspot/src/share/vm/code/codeCache.hpp | 7 +-
hotspot/src/share/vm/memory/heap.cpp | 272 +++++++++++----------
hotspot/src/share/vm/memory/heap.hpp | 30 ++-
hotspot/src/share/vm/runtime/arguments.cpp | 2 +
hotspot/src/share/vm/runtime/globals.hpp | 8 +-
6 files changed, 201 insertions(+), 168 deletions(-)
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index 3d7758304a8..b3a857c2062 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -198,14 +198,12 @@ CodeBlob* CodeCache::allocate(int size, bool is_critical) {
}
maxCodeCacheUsed = MAX2(maxCodeCacheUsed, ((address)_heap->high_boundary() -
(address)_heap->low_boundary()) - unallocated_capacity());
- verify_if_often();
print_trace("allocation", cb, size);
return cb;
}
void CodeCache::free(CodeBlob* cb) {
assert_locked_or_safepoint(CodeCache_lock);
- verify_if_often();
print_trace("free", cb);
if (cb->is_nmethod()) {
@@ -221,7 +219,6 @@ void CodeCache::free(CodeBlob* cb) {
_heap->deallocate(cb);
- verify_if_often();
assert(_number_of_blobs >= 0, "sanity check");
}
@@ -244,12 +241,6 @@ void CodeCache::commit(CodeBlob* cb) {
}
-void CodeCache::flush() {
- assert_locked_or_safepoint(CodeCache_lock);
- Unimplemented();
-}
-
-
// Iteration over CodeBlobs
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
@@ -269,7 +260,7 @@ bool CodeCache::contains(void *p) {
CodeBlob* CodeCache::find_blob(void* start) {
CodeBlob* result = find_blob_unsafe(start);
if (result == NULL) return NULL;
- // We could potientially look up non_entrant methods
+ // We could potentially look up non_entrant methods
guarantee(!result->is_zombie() || result->is_locked_by_vm() || is_error_reported(), "unsafe access to zombie method");
return result;
}
@@ -741,17 +732,26 @@ void CodeCache::report_codemem_full() {
}
}
+void CodeCache::print_memory_overhead() {
+ size_t wasted_bytes = 0;
+ CodeBlob *cb;
+ for (cb = first(); cb != NULL; cb = next(cb)) {
+ HeapBlock* heap_block = ((HeapBlock*)cb) - 1;
+ wasted_bytes += heap_block->length() * CodeCacheSegmentSize - cb->size();
+ }
+ // Print bytes that are allocated in the freelist
+ ttyLocker ttl;
+ tty->print_cr("Number of elements in freelist: %d", freelist_length());
+ tty->print_cr("Allocated in freelist: %dkB", bytes_allocated_in_freelist()/K);
+ tty->print_cr("Unused bytes in CodeBlobs: %dkB", (int)(wasted_bytes/K));
+ tty->print_cr("Segment map size: %dkB", allocated_segments()/K); // 1 byte per segment
+}
+
//------------------------------------------------------------------------------------------------
// Non-product version
#ifndef PRODUCT
-void CodeCache::verify_if_often() {
- if (VerifyCodeCacheOften) {
- _heap->verify();
- }
-}
-
void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) {
if (PrintCodeCache2) { // Need to add a new flag
ResourceMark rm;
@@ -774,7 +774,7 @@ void CodeCache::print_internals() {
int nmethodUnloaded = 0;
int nmethodJava = 0;
int nmethodNative = 0;
- int maxCodeSize = 0;
+ int max_nm_size = 0;
ResourceMark rm;
CodeBlob *cb;
@@ -798,13 +798,11 @@ void CodeCache::print_internals() {
if(nm->is_not_entrant()) { nmethodNotEntrant++; }
if(nm->is_zombie()) { nmethodZombie++; }
if(nm->is_unloaded()) { nmethodUnloaded++; }
- if(nm->is_native_method()) { nmethodNative++; }
+ if(nm->method() != NULL && nm->is_native_method()) { nmethodNative++; }
if(nm->method() != NULL && nm->is_java_method()) {
nmethodJava++;
- if (nm->insts_size() > maxCodeSize) {
- maxCodeSize = nm->insts_size();
- }
+ max_nm_size = MAX2(max_nm_size, nm->size());
}
} else if (cb->is_runtime_stub()) {
runtimeStubCount++;
@@ -820,18 +818,19 @@ void CodeCache::print_internals() {
}
int bucketSize = 512;
- int bucketLimit = maxCodeSize / bucketSize + 1;
+ int bucketLimit = max_nm_size / bucketSize + 1;
int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode);
- memset(buckets,0,sizeof(int) * bucketLimit);
+ memset(buckets, 0, sizeof(int) * bucketLimit);
for (cb = first(); cb != NULL; cb = next(cb)) {
if (cb->is_nmethod()) {
nmethod* nm = (nmethod*)cb;
if(nm->is_java_method()) {
- buckets[nm->insts_size() / bucketSize]++;
- }
+ buckets[nm->size() / bucketSize]++;
+ }
}
}
+
tty->print_cr("Code Cache Entries (total of %d)",total);
tty->print_cr("-------------------------------------------------");
tty->print_cr("nmethods: %d",nmethodCount);
@@ -858,6 +857,7 @@ void CodeCache::print_internals() {
}
FREE_C_HEAP_ARRAY(int, buckets, mtCode);
+ print_memory_overhead();
}
#endif // !PRODUCT
diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp
index e190b11ae7e..f9f656cc35a 100644
--- a/hotspot/src/share/vm/code/codeCache.hpp
+++ b/hotspot/src/share/vm/code/codeCache.hpp
@@ -58,12 +58,13 @@ class CodeCache : AllStatic {
static bool _needs_cache_clean;
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
- static void verify_if_often() PRODUCT_RETURN;
-
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
static int _codemem_full_count;
+ static size_t bytes_allocated_in_freelist() { return _heap->allocated_in_freelist(); }
+ static int allocated_segments() { return _heap->allocated_segments(); }
+ static size_t freelist_length() { return _heap->freelist_length(); }
public:
@@ -78,7 +79,6 @@ class CodeCache : AllStatic {
static int alignment_unit(); // guaranteed alignment of all CodeBlobs
static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
static void free(CodeBlob* cb); // frees a CodeBlob
- static void flush(); // flushes all CodeBlobs
static bool contains(void *p); // returns whether p is included
static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs
static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs
@@ -150,6 +150,7 @@ class CodeCache : AllStatic {
// Printing/debugging
static void print(); // prints summary
static void print_internals();
+ static void print_memory_overhead();
static void verify(); // verifies the code cache
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp
index a241af2eee9..db0105fb3a1 100644
--- a/hotspot/src/share/vm/memory/heap.cpp
+++ b/hotspot/src/share/vm/memory/heap.cpp
@@ -43,6 +43,7 @@ CodeHeap::CodeHeap() {
_next_segment = 0;
_freelist = NULL;
_freelist_segments = 0;
+ _freelist_length = 0;
}
@@ -53,7 +54,7 @@ void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) {
address p = (address)_segmap.low() + beg;
address q = (address)_segmap.low() + end;
// initialize interval
- while (p < q) *p++ = 0xFF;
+ while (p < q) *p++ = free_sentinel;
}
@@ -67,7 +68,7 @@ void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) {
int i = 0;
while (p < q) {
*p++ = i++;
- if (i == 0xFF) i = 1;
+ if (i == free_sentinel) i = 1;
}
}
@@ -139,11 +140,6 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
}
-void CodeHeap::release() {
- Unimplemented();
-}
-
-
bool CodeHeap::expand_by(size_t size) {
// expand _memory space
size_t dm = align_to_page_size(_memory.committed_size() + size) - _memory.committed_size();
@@ -157,8 +153,8 @@ bool CodeHeap::expand_by(size_t size) {
assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking");
// expand _segmap space
size_t ds = align_to_page_size(_number_of_committed_segments) - _segmap.committed_size();
- if (ds > 0) {
- if (!_segmap.expand_by(ds)) return false;
+ if ((ds > 0) && !_segmap.expand_by(ds)) {
+ return false;
}
assert(_segmap.committed_size() >= (size_t) _number_of_committed_segments, "just checking");
// initialize additional segmap entries
@@ -167,12 +163,6 @@ bool CodeHeap::expand_by(size_t size) {
return true;
}
-
-void CodeHeap::shrink_by(size_t size) {
- Unimplemented();
-}
-
-
void CodeHeap::clear() {
_next_segment = 0;
mark_segmap_as_free(0, _number_of_committed_segments);
@@ -180,26 +170,23 @@ void CodeHeap::clear() {
void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
- size_t number_of_segments = size_to_segments(instance_size + sizeof(HeapBlock));
+ size_t number_of_segments = size_to_segments(instance_size + header_size());
assert(segments_to_size(number_of_segments) >= sizeof(FreeBlock), "not enough room for FreeList");
// First check if we can satisfy request from freelist
- debug_only(verify());
+ NOT_PRODUCT(verify());
HeapBlock* block = search_freelist(number_of_segments, is_critical);
- debug_only(if (VerifyCodeCacheOften) verify());
+ NOT_PRODUCT(verify());
+
if (block != NULL) {
assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
assert(!block->free(), "must be marked free");
-#ifdef ASSERT
- memset((void *)block->allocated_space(), badCodeHeapNewVal, instance_size);
-#endif
+ DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
return block->allocated_space();
}
// Ensure minimum size for allocation to the heap.
- if (number_of_segments < CodeCacheMinBlockLength) {
- number_of_segments = CodeCacheMinBlockLength;
- }
+ number_of_segments = MAX2((int)CodeCacheMinBlockLength, (int)number_of_segments);
if (!is_critical) {
// Make sure the allocation fits in the unallocated heap without using
@@ -215,9 +202,7 @@ void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
HeapBlock* b = block_at(_next_segment);
b->initialize(number_of_segments);
_next_segment += number_of_segments;
-#ifdef ASSERT
- memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size);
-#endif
+ DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
return b->allocated_space();
} else {
return NULL;
@@ -230,28 +215,56 @@ void CodeHeap::deallocate(void* p) {
// Find start of HeapBlock
HeapBlock* b = (((HeapBlock *)p) - 1);
assert(b->allocated_space() == p, "sanity check");
-#ifdef ASSERT
- memset((void *)b->allocated_space(),
- badCodeHeapFreeVal,
- segments_to_size(b->length()) - sizeof(HeapBlock));
-#endif
+ DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapFreeVal,
+ segments_to_size(b->length()) - sizeof(HeapBlock)));
add_to_freelist(b);
-
- debug_only(if (VerifyCodeCacheOften) verify());
+ NOT_PRODUCT(verify());
}
-
+/**
+ * Uses segment map to find the the start (header) of a nmethod. This works as follows:
+ * The memory of the code cache is divided into 'segments'. The size of a segment is
+ * determined by -XX:CodeCacheSegmentSize=XX. Allocation in the code cache can only
+ * happen at segment boundaries. A pointer in the code cache can be mapped to a segment
+ * by calling segment_for(addr). Each time memory is requested from the code cache,
+ * the segmap is updated accordingly. See the following example, which illustrates the
+ * state of code cache and the segment map: (seg -> segment, nm ->nmethod)
+ *
+ * code cache segmap
+ * ----------- ---------
+ * seg 1 | nm 1 | -> | 0 |
+ * seg 2 | nm 1 | -> | 1 |
+ * ... | nm 1 | -> | .. |
+ * seg m | nm 2 | -> | 0 |
+ * seg m+1 | nm 2 | -> | 1 |
+ * ... | nm 2 | -> | 2 |
+ * ... | nm 2 | -> | .. |
+ * ... | nm 2 | -> | 0xFE |
+ * seg m+n | nm 2 | -> | 1 |
+ * ... | nm 2 | -> | |
+ *
+ * A value of '0' in the segmap indicates that this segment contains the beginning of
+ * an nmethod. Let's walk through a simple example: If we want to find the start of
+ * an nmethod that falls into seg 2, we read the value of the segmap[2]. The value
+ * is an offset that points to the segment that contains the start of the nmethod.
+ * Another example: If we want to get the start of nm 2, and we happen to get a pointer
+ * that points to seg m+n, we first read seg[n+m], which returns '1'. So we have to
+ * do one more read of the segmap[m+n-1] to finally get the segment header.
+ */
void* CodeHeap::find_start(void* p) const {
if (!contains(p)) {
return NULL;
}
- size_t i = segment_for(p);
- address b = (address)_segmap.low();
- if (b[i] == 0xFF) {
+ size_t seg_idx = segment_for(p);
+ address seg_map = (address)_segmap.low();
+ if (is_segment_unused(seg_map[seg_idx])) {
return NULL;
}
- while (b[i] > 0) i -= (int)b[i];
- HeapBlock* h = block_at(i);
+ while (seg_map[seg_idx] > 0) {
+ seg_idx -= (int)seg_map[seg_idx];
+ }
+
+ HeapBlock* h = block_at(seg_idx);
if (h->free()) {
return NULL;
}
@@ -272,7 +285,7 @@ size_t CodeHeap::alignment_offset() const {
}
// Finds the next free heapblock. If the current one is free, that it returned
-void* CodeHeap::next_free(HeapBlock *b) const {
+void* CodeHeap::next_free(HeapBlock* b) const {
// Since free blocks are merged, there is max. on free block
// between two used ones
if (b != NULL && b->free()) b = next_block(b);
@@ -287,7 +300,7 @@ HeapBlock* CodeHeap::first_block() const {
return NULL;
}
-HeapBlock *CodeHeap::block_start(void *q) const {
+HeapBlock* CodeHeap::block_start(void* q) const {
HeapBlock* b = (HeapBlock*)find_start(q);
if (b == NULL) return NULL;
return b - 1;
@@ -312,6 +325,10 @@ size_t CodeHeap::max_capacity() const {
return _memory.reserved_size();
}
+int CodeHeap::allocated_segments() const {
+ return (int)_next_segment;
+}
+
size_t CodeHeap::allocated_capacity() const {
// size of used heap - size on freelist
return segments_to_size(_next_segment - _freelist_segments);
@@ -325,7 +342,7 @@ size_t CodeHeap::heap_unallocated_capacity() const {
// Free list management
-FreeBlock *CodeHeap::following_block(FreeBlock *b) {
+FreeBlock* CodeHeap::following_block(FreeBlock *b) {
return (FreeBlock*)(((address)b) + _segment_size * b->length());
}
@@ -343,7 +360,7 @@ void CodeHeap::insert_after(FreeBlock* a, FreeBlock* b) {
}
// Try to merge this block with the following block
-void CodeHeap::merge_right(FreeBlock *a) {
+bool CodeHeap::merge_right(FreeBlock* a) {
assert(a->free(), "must be a free block");
if (following_block(a) == a->link()) {
assert(a->link() != NULL && a->link()->free(), "must be free too");
@@ -353,13 +370,20 @@ void CodeHeap::merge_right(FreeBlock *a) {
// Update find_start map
size_t beg = segment_for(a);
mark_segmap_as_used(beg, beg + a->length());
+ _freelist_length--;
+ return true;
}
+ return false;
}
-void CodeHeap::add_to_freelist(HeapBlock *a) {
+
+void CodeHeap::add_to_freelist(HeapBlock* a) {
FreeBlock* b = (FreeBlock*)a;
+ _freelist_length++;
+
assert(b != _freelist, "cannot be removed twice");
+
// Mark as free and update free space count
_freelist_segments += b->length();
b->set_free();
@@ -371,95 +395,96 @@ void CodeHeap::add_to_freelist(HeapBlock *a) {
return;
}
- // Scan for right place to put into list. List
- // is sorted by increasing addresses
- FreeBlock* prev = NULL;
- FreeBlock* cur = _freelist;
- while(cur != NULL && cur < b) {
- assert(prev == NULL || prev < cur, "must be ordered");
- prev = cur;
- cur = cur->link();
- }
-
- assert( (prev == NULL && b < _freelist) ||
- (prev < b && (cur == NULL || b < cur)), "list must be ordered");
-
- if (prev == NULL) {
+ // Since the freelist is ordered (smaller addresses -> larger addresses) and the
+ // element we want to insert into the freelist has a smaller address than the first
+ // element, we can simply add 'b' as the first element and we are done.
+ if (b < _freelist) {
// Insert first in list
b->set_link(_freelist);
_freelist = b;
merge_right(_freelist);
- } else {
- insert_after(prev, b);
+ return;
}
+
+ // Scan for right place to put into list. List
+ // is sorted by increasing addresses
+ FreeBlock* prev = _freelist;
+ FreeBlock* cur = _freelist->link();
+ while(cur != NULL && cur < b) {
+ assert(prev < cur, "Freelist must be ordered");
+ prev = cur;
+ cur = cur->link();
+ }
+ assert((prev < b) && (cur == NULL || b < cur), "free-list must be ordered");
+ insert_after(prev, b);
}
-// Search freelist for an entry on the list with the best fit
-// Return NULL if no one was found
+/**
+ * Search freelist for an entry on the list with the best fit.
+ * @return NULL, if no one was found
+ */
FreeBlock* CodeHeap::search_freelist(size_t length, bool is_critical) {
- FreeBlock *best_block = NULL;
- FreeBlock *best_prev = NULL;
- size_t best_length = 0;
+ FreeBlock* found_block = NULL;
+ FreeBlock* found_prev = NULL;
+ size_t found_length = 0;
- // Search for smallest block which is bigger than length
- FreeBlock *prev = NULL;
- FreeBlock *cur = _freelist;
+ FreeBlock* prev = NULL;
+ FreeBlock* cur = _freelist;
+ const size_t critical_boundary = (size_t)high_boundary() - CodeCacheMinimumFreeSpace;
+
+ // Search for first block that fits
while(cur != NULL) {
- size_t l = cur->length();
- if (l >= length && (best_block == NULL || best_length > l)) {
-
+ if (cur->length() >= length) {
// Non critical allocations are not allowed to use the last part of the code heap.
- if (!is_critical) {
- // Make sure the end of the allocation doesn't cross into the last part of the code heap
- if (((size_t)cur + length) > ((size_t)high_boundary() - CodeCacheMinimumFreeSpace)) {
- // the freelist is sorted by address - if one fails, all consecutive will also fail.
- break;
- }
+ // Make sure the end of the allocation doesn't cross into the last part of the code heap.
+ if (!is_critical && (((size_t)cur + length) > critical_boundary)) {
+ // The freelist is sorted by address - if one fails, all consecutive will also fail.
+ break;
}
+ // Remember block, its previous element, and its length
+ found_block = cur;
+ found_prev = prev;
+ found_length = found_block->length();
- // Remember best block, its previous element, and its length
- best_block = cur;
- best_prev = prev;
- best_length = best_block->length();
+ break;
}
-
// Next element in list
prev = cur;
cur = cur->link();
}
- if (best_block == NULL) {
+ if (found_block == NULL) {
// None found
return NULL;
}
- assert((best_prev == NULL && _freelist == best_block ) ||
- (best_prev != NULL && best_prev->link() == best_block), "sanity check");
-
// Exact (or at least good enough) fit. Remove from list.
// Don't leave anything on the freelist smaller than CodeCacheMinBlockLength.
- if (best_length < length + CodeCacheMinBlockLength) {
- length = best_length;
- if (best_prev == NULL) {
- assert(_freelist == best_block, "sanity check");
+ if (found_length - length < CodeCacheMinBlockLength) {
+ _freelist_length--;
+ length = found_length;
+ if (found_prev == NULL) {
+ assert(_freelist == found_block, "sanity check");
_freelist = _freelist->link();
} else {
+ assert((found_prev->link() == found_block), "sanity check");
// Unmap element
- best_prev->set_link(best_block->link());
+ found_prev->set_link(found_block->link());
}
} else {
// Truncate block and return a pointer to the following block
- best_block->set_length(best_length - length);
- best_block = following_block(best_block);
// Set used bit and length on new block
- size_t beg = segment_for(best_block);
+ found_block->set_length(found_length - length);
+ found_block = following_block(found_block);
+
+ size_t beg = segment_for(found_block);
mark_segmap_as_used(beg, beg + length);
- best_block->set_length(length);
+ found_block->set_length(length);
}
- best_block->set_used();
+ found_block->set_used();
_freelist_segments -= length;
- return best_block;
+ return found_block;
}
//----------------------------------------------------------------------------
@@ -471,33 +496,34 @@ void CodeHeap::print() {
tty->print_cr("The Heap");
}
-#endif
-
void CodeHeap::verify() {
- // Count the number of blocks on the freelist, and the amount of space
- // represented.
- int count = 0;
- size_t len = 0;
- for(FreeBlock* b = _freelist; b != NULL; b = b->link()) {
- len += b->length();
- count++;
- }
+ if (VerifyCodeCache) {
+ size_t len = 0;
+ int count = 0;
+ for(FreeBlock* b = _freelist; b != NULL; b = b->link()) {
+ len += b->length();
+ count++;
+ // Check if we have merged all free blocks
+ assert(merge_right(b) == false, "Missed merging opportunity");
+ }
+ // Verify that freelist contains the right amount of free space
+ assert(len == _freelist_segments, "wrong freelist");
- // Verify that freelist contains the right amount of free space
- // guarantee(len == _freelist_segments, "wrong freelist");
+ for(HeapBlock* h = first_block(); h != NULL; h = next_block(h)) {
+ if (h->free()) count--;
+ }
+ // Verify that the freelist contains the same number of blocks
+ // than free blocks found on the full list.
+ assert(count == 0, "missing free blocks");
- // Verify that the number of free blocks is not out of hand.
- static int free_block_threshold = 10000;
- if (count > free_block_threshold) {
- warning("CodeHeap: # of free blocks > %d", free_block_threshold);
- // Double the warning limit
- free_block_threshold *= 2;
+ // Verify that the number of free blocks is not out of hand.
+ static int free_block_threshold = 10000;
+ if (count > free_block_threshold) {
+ warning("CodeHeap: # of free blocks > %d", free_block_threshold);
+ // Double the warning limit
+ free_block_threshold *= 2;
+ }
}
-
- // Verify that the freelist contains the same number of free blocks that is
- // found on the full list.
- for(HeapBlock *h = first_block(); h != NULL; h = next_block(h)) {
- if (h->free()) count--;
- }
- // guarantee(count == 0, "missing free blocks");
}
+
+#endif
diff --git a/hotspot/src/share/vm/memory/heap.hpp b/hotspot/src/share/vm/memory/heap.hpp
index e271d1be2fc..849931ee70b 100644
--- a/hotspot/src/share/vm/memory/heap.hpp
+++ b/hotspot/src/share/vm/memory/heap.hpp
@@ -92,24 +92,28 @@ class CodeHeap : public CHeapObj {
FreeBlock* _freelist;
size_t _freelist_segments; // No. of segments in freelist
+ int _freelist_length;
+
+ enum { free_sentinel = 0xFF };
// Helper functions
size_t size_to_segments(size_t size) const { return (size + _segment_size - 1) >> _log2_segment_size; }
size_t segments_to_size(size_t number_of_segments) const { return number_of_segments << _log2_segment_size; }
size_t segment_for(void* p) const { return ((char*)p - _memory.low()) >> _log2_segment_size; }
+ bool is_segment_unused(int val) const { return val == free_sentinel; }
HeapBlock* block_at(size_t i) const { return (HeapBlock*)(_memory.low() + (i << _log2_segment_size)); }
void mark_segmap_as_free(size_t beg, size_t end);
void mark_segmap_as_used(size_t beg, size_t end);
// Freelist management helpers
- FreeBlock* following_block(FreeBlock *b);
+ FreeBlock* following_block(FreeBlock* b);
void insert_after(FreeBlock* a, FreeBlock* b);
- void merge_right (FreeBlock* a);
+ bool merge_right (FreeBlock* a);
// Toplevel freelist management
- void add_to_freelist(HeapBlock *b);
+ void add_to_freelist(HeapBlock* b);
FreeBlock* search_freelist(size_t length, bool is_critical);
// Iteration helpers
@@ -120,20 +124,18 @@ class CodeHeap : public CHeapObj {
// to perform additional actions on creation of executable code
void on_code_mapping(char* base, size_t size);
+ void clear(); // clears all heap contents
public:
CodeHeap();
// Heap extents
bool reserve(size_t reserved_size, size_t committed_size, size_t segment_size);
- void release(); // releases all allocated memory
bool expand_by(size_t size); // expands committed memory by size
- void shrink_by(size_t size); // shrinks committed memory by size
- void clear(); // clears all heap contents
// Memory allocation
void* allocate (size_t size, bool is_critical); // allocates a block of size or returns NULL
- void deallocate(void* p); // deallocates a block
+ void deallocate(void* p); // deallocates a block
// Attributes
char* low_boundary() const { return _memory.low_boundary (); }
@@ -141,12 +143,13 @@ class CodeHeap : public CHeapObj {
char* high_boundary() const { return _memory.high_boundary(); }
bool contains(const void* p) const { return low_boundary() <= p && p < high(); }
- void* find_start(void* p) const; // returns the block containing p or NULL
- size_t alignment_unit() const; // alignment of any block
- size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
- static size_t header_size(); // returns the header size for each heap block
+ void* find_start(void* p) const; // returns the block containing p or NULL
+ size_t alignment_unit() const; // alignment of any block
+ size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
+ static size_t header_size(); // returns the header size for each heap block
- // Iteration
+ size_t allocated_in_freelist() const { return _freelist_segments * CodeCacheSegmentSize; }
+ int freelist_length() const { return _freelist_length; } // number of elements in the freelist
// returns the first block or NULL
void* first() const { return next_free(first_block()); }
@@ -156,6 +159,7 @@ class CodeHeap : public CHeapObj {
// Statistics
size_t capacity() const;
size_t max_capacity() const;
+ int allocated_segments() const;
size_t allocated_capacity() const;
size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); }
@@ -164,7 +168,7 @@ private:
public:
// Debugging
- void verify();
+ void verify() PRODUCT_RETURN;
void print() PRODUCT_RETURN;
};
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index d6d8583d697..14ff5167cb6 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -2407,6 +2407,8 @@ bool Arguments::check_vm_args_consistency() {
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
+ status &= verify_interval(CodeCacheMinBlockLength, 1, 100, "CodeCacheMinBlockLength");
+ status &= verify_interval(CodeCacheSegmentSize, 1, 1024, "CodeCacheSegmentSize");
// TieredCompilation needs at least 2 compiler threads.
const int num_min_compiler_threads = (TieredCompilation && (TieredStopAtLevel >= CompLevel_full_optimization)) ? 2 : 1;
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 30f7007066d..945e8ea667e 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -814,8 +814,8 @@ class CommandLineFlags {
product(bool, PrintOopAddress, false, \
"Always print the location of the oop") \
\
- notproduct(bool, VerifyCodeCacheOften, false, \
- "Verify compiled-code cache often") \
+ notproduct(bool, VerifyCodeCache, false, \
+ "Verify code cache on memory allocation/deallocation") \
\
develop(bool, ZapDeadCompiledLocals, false, \
"Zap dead locals in compiler frames") \
@@ -3296,8 +3296,8 @@ class CommandLineFlags {
"disable this feature") \
\
/* code cache parameters */ \
- /* ppc64 has large code-entry alignment. */ \
- develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64), \
+ /* ppc64/tiered compilation has large code-entry alignment. */ \
+ develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)),\
"Code cache segment size (in bytes) - smallest unit of " \
"allocation") \
\
From 16962804f32708b10babc1f40f2bc12a805830a1 Mon Sep 17 00:00:00 2001
From: Jan Lahoda
Date: Fri, 7 Mar 2014 13:35:56 +0100
Subject: [PATCH 041/116] 8034854: outer_class_info_index of synthetic class is
not zero
Auxiliary synthetic anonymous classes should not have an outer class specified in the InnerClasses attribute.
Reviewed-by: vromero, jjg, abuckley
---
.../com/sun/tools/javac/jvm/ClassWriter.java | 2 +-
.../InnerClasses/SyntheticClasses.java | 97 +++++++++++++++++++
2 files changed, 98 insertions(+), 1 deletion(-)
create mode 100644 langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java
diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
index 5e7293d74d3..13e910ce559 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
@@ -1037,7 +1037,7 @@ public class ClassWriter extends ClassFile {
}
databuf.appendChar(pool.get(inner));
databuf.appendChar(
- inner.owner.kind == TYP ? pool.get(inner.owner) : 0);
+ inner.owner.kind == TYP && !inner.name.isEmpty() ? pool.get(inner.owner) : 0);
databuf.appendChar(
!inner.name.isEmpty() ? pool.get(inner.name) : 0);
databuf.appendChar(flags);
diff --git a/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java b/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java
new file mode 100644
index 00000000000..58a8f9aa186
--- /dev/null
+++ b/langtools/test/tools/javac/classfiles/InnerClasses/SyntheticClasses.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8034854
+ * @summary Verify that the InnerClasses attribute has outer_class_info_index zero if it has
+ * inner_name_index zero (for synthetic classes)
+ * @compile SyntheticClasses.java
+ * @run main SyntheticClasses
+ */
+
+import java.io.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+
+public class SyntheticClasses {
+
+ public static void main(String[] args) throws IOException, ConstantPoolException {
+ new SyntheticClasses().run();
+ }
+
+ private void run() throws IOException, ConstantPoolException {
+ File testClasses = new File(System.getProperty("test.classes"));
+ for (File classFile : testClasses.listFiles()) {
+ ClassFile cf = ClassFile.read(classFile);
+ if (cf.getName().matches(".*\\$[0-9]+")) {
+ EnclosingMethod_attribute encl =
+ (EnclosingMethod_attribute) cf.getAttribute(Attribute.EnclosingMethod);
+ if (encl != null) {
+ if (encl.method_index != 0)
+ throw new IllegalStateException("Invalid EnclosingMethod.method_index: " +
+ encl.method_index + ".");
+ }
+ }
+ InnerClasses_attribute attr =
+ (InnerClasses_attribute) cf.getAttribute(Attribute.InnerClasses);
+ if (attr != null) {
+ for (InnerClasses_attribute.Info info : attr.classes) {
+ if (cf.major_version < 51)
+ throw new IllegalStateException();
+ if (info.inner_name_index == 0 && info.outer_class_info_index != 0)
+ throw new IllegalStateException("Invalid outer_class_info_index=" +
+ info.outer_class_info_index +
+ "; inner_name_index=" +
+ info.inner_name_index + ".");
+ }
+ }
+ }
+ }
+}
+
+class SyntheticConstructorAccessTag {
+
+ private static class A {
+ private A(){}
+ }
+
+ public void test() {
+ new A();
+ }
+}
+
+class SyntheticEnumMapping {
+ private int convert(E e) {
+ switch (e) {
+ case A: return 0;
+ default: return -1;
+ }
+ }
+ enum E { A }
+}
+
+interface SyntheticAssertionsDisabled {
+ public default void test() {
+ assert false;
+ }
+}
From 18c3f81053e9b26565510e8cc5ecc11712b22c3c Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 7 Mar 2014 14:56:08 +0100
Subject: [PATCH 042/116] 8036611: Cleanup of handling of properties and other
java resources in the build
Reviewed-by: tbell, ihse
---
make/common/JavaCompilation.gmk | 45 +++++++++++++++++++++++----------
1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index c2dd54b2be5..5eed2ff701c 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -336,7 +336,20 @@ endef
# Previously this was inconsistently done in different repositories.
# This is the new clean standard. Though it is to be superseded by
# a standard annotation processor from with sjavac.
-define add_file_to_copy_and_clean
+#
+# The sed expression does this:
+# 1. Add a backslash before any :, = or ! that do not have a backslash already.
+# 2. Apply the file unicode2x.sed which does a whole bunch of \u00XX to \xXX
+# conversions.
+# 3. Delete all lines starting with #.
+# 4. Delete empty lines.
+# 5. Append lines ending with \ with the next line.
+# 6. Remove leading and trailing white space.
+# 7. Replace the first \= with just =.
+# 8. Finally it's all sorted to create a stable output.
+#
+# It is assumed that = is the character used for separating names and values.
+define add_file_to_clean
# param 1 = BUILD_MYPACKAGE
# parma 2 = The source file to copy and clean.
$2_TARGET:=$2
@@ -345,7 +358,8 @@ define add_file_to_copy_and_clean
# Now we can setup the depency that will trigger the copying.
$$($1_BIN)$$($2_TARGET) : $2
$(MKDIR) -p $$(@D)
- $(CAT) $$< | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' -e 's/#.*/#/g' \
+ $(CAT) $$< | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' \
+ -e 's/\([^\\]\)!/\1\\!/g' -e 's/#.*/#/g' \
| $(SED) -f "$(SRC_ROOT)/make/common/support/unicode2x.sed" \
| $(SED) -e '/^#/d' -e '/^$$$$/d' \
-e :a -e '/\\$$$$/N; s/\\\n//; ta' \
@@ -376,8 +390,9 @@ define SetupJavaCompilation
# INCLUDES:=myapp.foo means will only compile java files in myapp.foo or any of its sub-packages.
# EXCLUDES:=myapp.foo means will do not compile java files in myapp.foo or any of its sub-packages.
# COPY:=.prp means copy all prp files to the corresponding package in BIN.
- # CLEAN:=.properties means copy and clean all properties file to the corresponding package in BIN.
# COPY_FILES:=myapp/foo/setting.txt means copy this file over to the package myapp/foo
+ # CLEAN:=.properties means copy and clean all properties file to the corresponding package in BIN.
+ # CLEAN_FILES:=myapp/foo/setting.txt means clean this file over to the package myapp/foo
# SRCZIP:=Create a src.zip based on the found sources and copied files.
# INCLUDE_FILES:="com/sun/SolarisFoobar.java" means only compile this file!
# EXCLUDE_FILES:="com/sun/SolarisFoobar.java" means do not compile this particular file!
@@ -437,7 +452,7 @@ define SetupJavaCompilation
endif
# Find all files to be copied from source to bin.
- ifneq (,$$($1_COPY))
+ ifneq (,$$($1_COPY)$$($1_COPY_FILES))
# Search for all files to be copied.
$1_ALL_COPIES := $$(filter $$(addprefix %,$$($1_COPY)),$$($1_ALL_SRCS))
# Copy these explicitly
@@ -452,20 +467,22 @@ define SetupJavaCompilation
ifneq (,$$($1_EXCLUDE_FILES))
$1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES))
endif
- # All files below META-INF are always copied.
- $1_ALL_COPIES += $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS))
- ifneq (,$$($1_ALL_COPIES))
- # Yep, there are files to be copied!
- $1_ALL_COPY_TARGETS:=
- $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i)))
- # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files!
- endif
+ endif
+ # All files below META-INF are always copied.
+ $1_ALL_COPIES += $$(filter $$(addsuffix /META-INF%,$$($1_SRC)),$$($1_ALL_SRCS))
+ ifneq (,$$($1_ALL_COPIES))
+ # Yep, there are files to be copied!
+ $1_ALL_COPY_TARGETS:=
+ $$(foreach i,$$($1_ALL_COPIES),$$(eval $$(call add_file_to_copy,$1,$$i)))
+ # Now we can depend on $$($1_ALL_COPY_TARGETS) to copy all files!
endif
# Find all property files to be copied and cleaned from source to bin.
- ifneq (,$$($1_CLEAN))
+ ifneq (,$$($1_CLEAN)$$($1_CLEAN_FILES))
# Search for all files to be copied.
$1_ALL_CLEANS := $$(filter $$(addprefix %,$$($1_CLEAN)),$$($1_ALL_SRCS))
+ # Clean these explicitly
+ $1_ALL_CLEANS += $$($1_CLEAN_FILES)
# Copy and clean must also respect filters.
ifneq (,$$($1_INCLUDES))
$1_ALL_CLEANS := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_CLEANS))
@@ -479,7 +496,7 @@ define SetupJavaCompilation
ifneq (,$$($1_ALL_CLEANS))
# Yep, there are files to be copied and cleaned!
$1_ALL_COPY_CLEAN_TARGETS:=
- $$(foreach i,$$($1_ALL_CLEANS),$$(eval $$(call add_file_to_copy_and_clean,$1,$$i)))
+ $$(foreach i,$$($1_ALL_CLEANS),$$(eval $$(call add_file_to_clean,$1,$$i)))
# Now we can depend on $$($1_ALL_COPY_CLEAN_TARGETS) to copy all files!
endif
endif
From d4486816f5a971dfb1721898ec6749c4b49de761 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 7 Mar 2014 14:57:08 +0100
Subject: [PATCH 043/116] 8036611: Cleanup of handling of properties and other
java resources in the build
Reviewed-by: tbell, ihse
---
jaxp/make/BuildJaxp.gmk | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/jaxp/make/BuildJaxp.gmk b/jaxp/make/BuildJaxp.gmk
index 7950b0cf8a1..57c184bc4ee 100644
--- a/jaxp/make/BuildJaxp.gmk
+++ b/jaxp/make/BuildJaxp.gmk
@@ -45,27 +45,11 @@ $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \
$(eval $(call SetupJavaCompilation,BUILD_JAXP, \
SETUP := GENERATE_NEWBYTECODE_DEBUG, \
SRC := $(JAXP_TOPDIR)/src, \
+ CLEAN := .properties, \
BIN := $(JAXP_OUTPUTDIR)/classes, \
- SRCZIP := $(JAXP_OUTPUTDIR)/dist/lib/src.zip))
-
-# Imitate the property cleaning mechanism in the old build. This will likely be replaced
-# by the unified functionality in JavaCompilation.gmk, but keep it the same as old build
-# for now, even though it actually breaks properties containing # in the value.
-# Using nawk to avoid solaris sed.
-$(JAXP_OUTPUTDIR)/classes/%.properties: $(JAXP_TOPDIR)/src/%.properties
- $(MKDIR) -p $(@D)
- $(RM) $@ $@.tmp
- $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp
- $(MV) $@.tmp $@
-
-SRC_PROP_FILES := $(shell $(FIND) $(JAXP_TOPDIR)/src -name "*.properties")
-TARGET_PROP_FILES := $(patsubst $(JAXP_TOPDIR)/src/%, $(JAXP_OUTPUTDIR)/classes/%, $(SRC_PROP_FILES))
-
-$(eval $(call SetupArchive,ARCHIVE_JAXP, $(BUILD_JAXP) $(TARGET_PROP_FILES), \
- SRCS := $(JAXP_OUTPUTDIR)/classes, \
- SUFFIXES := .class .properties, \
+ SRCZIP := $(JAXP_OUTPUTDIR)/dist/lib/src.zip, \
JAR := $(JAXP_OUTPUTDIR)/dist/lib/classes.jar))
-all: $(JAXP_OUTPUTDIR)/dist/lib/classes.jar $(JAXP_OUTPUTDIR)/dist/lib/src.zip
+all: $(BUILD_JAXP)
.PHONY: default all
From 93e8215def82e58f5eb1d02ed2be9119f1d95840 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 7 Mar 2014 14:57:16 +0100
Subject: [PATCH 044/116] 8036611: Cleanup of handling of properties and other
java resources in the build
Reviewed-by: tbell, ihse
---
jaxws/make/BuildJaxws.gmk | 28 ++--------------------------
1 file changed, 2 insertions(+), 26 deletions(-)
diff --git a/jaxws/make/BuildJaxws.gmk b/jaxws/make/BuildJaxws.gmk
index 204dd47fb53..1c159965dd3 100644
--- a/jaxws/make/BuildJaxws.gmk
+++ b/jaxws/make/BuildJaxws.gmk
@@ -42,11 +42,10 @@ $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
-# Dummy here is needed to trigger copying of META-INF
$(eval $(call SetupJavaCompilation,BUILD_JAF, \
SETUP := GENERATE_NEWBYTECODE_DEBUG, \
SRC := $(JAXWS_TOPDIR)/src/share/jaf_classes, \
- COPY := "dummy", \
+ CLEAN := .properties, \
BIN := $(JAXWS_OUTPUTDIR)/jaf_classes))
$(eval $(call SetupJavaCompilation,BUILD_JAXWS, \
@@ -57,6 +56,7 @@ $(eval $(call SetupJavaCompilation,BUILD_JAXWS, \
COPY_FILES := $(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/tools/internal/xjc/runtime/JAXBContextFactory.java \
$(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/tools/internal/xjc/runtime/ZeroOneBooleanAdapter.java \
$(JAXWS_TOPDIR)/src/share/jaxws_classes/com/sun/xml/internal/ws/assembler/jaxws-tubes-default.xml, \
+ CLEAN := .properties, \
ADD_JAVAC_FLAGS = -Xbootclasspath/p:$(OUTPUT_ROOT)/jaxp/dist/lib/classes.jar))
$(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.ws.wscompile.Plugin: \
@@ -73,30 +73,6 @@ $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.xjc.Pl
BUILD_JAXWS += $(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.ws.wscompile.Plugin \
$(JAXWS_OUTPUTDIR)/jaxws_classes/META-INF/services/com.sun.tools.internal.xjc.Plugin
-# Imitate the property cleaning mechanism in the old build. This will likely be replaced
-# by the unified functionality in JavaCompilation.gmk, but keep it the same as old build
-# for now, even though it actually breaks properties containing # in the value.
-# Using nawk to avoid solaris sed.
-$(JAXWS_OUTPUTDIR)/jaxws_classes/%.properties: $(JAXWS_TOPDIR)/src/share/jaxws_classes/%.properties
- $(MKDIR) -p $(@D)
- $(RM) $@ $@.tmp
- $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp
- $(MV) $@.tmp $@
-
-JAXWS_SRC_PROP_FILES := $(shell $(FIND) $(JAXWS_TOPDIR)/src/share/jaxws_classes -name "*.properties")
-TARGET_PROP_FILES := $(patsubst $(JAXWS_TOPDIR)/src/share/jaxws_classes/%, \
- $(JAXWS_OUTPUTDIR)/jaxws_classes/%, $(JAXWS_SRC_PROP_FILES))
-
-$(JAXWS_OUTPUTDIR)/jaf_classes/%.properties: $(JAXWS_TOPDIR)/src/share/jaf_classes/%.properties
- $(MKDIR) -p $(@D)
- $(RM) $@ $@.tmp
- $(CAT) $< | LANG=C $(NAWK) '{ sub(/#.*$$/,"#"); print }' > $@.tmp
- $(MV) $@.tmp $@
-
-JAF_SRC_PROP_FILES := $(shell $(FIND) $(JAXWS_TOPDIR)/src/share/jaf_classes -name "*.properties")
-TARGET_PROP_FILES += $(patsubst $(JAXWS_TOPDIR)/src/share/jaf_classes/%, \
- $(JAXWS_OUTPUTDIR)/jaf_classes/%, $(JAF_SRC_PROP_FILES))
-
$(eval $(call SetupArchive,ARCHIVE_JAXWS, $(BUILD_JAXWS) $(BUILD_JAF) $(TARGET_PROP_FILES), \
SRCS := $(JAXWS_OUTPUTDIR)/jaxws_classes $(JAXWS_OUTPUTDIR)/jaf_classes, \
SUFFIXES := .class .properties .xsd .xml .java \
From 0a87e0cbbfafdbbff9c27e86f99f8ffa6c0cefe1 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 7 Mar 2014 15:02:55 +0100
Subject: [PATCH 045/116] 8036611: Cleanup of handling of properties and other
java resources in the build
Reviewed-by: tbell, ihse
---
corba/make/CompileCorba.gmk | 8 +-
corba/make/GensrcCorba.gmk | 30 +-
.../stripproperties/StripPropertiesCorba.java | 288 ------------------
3 files changed, 11 insertions(+), 315 deletions(-)
delete mode 100644 corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java
diff --git a/corba/make/CompileCorba.gmk b/corba/make/CompileCorba.gmk
index f50d4ca4687..225258c2080 100644
--- a/corba/make/CompileCorba.gmk
+++ b/corba/make/CompileCorba.gmk
@@ -45,16 +45,18 @@ $(eval $(call SetupJavaCompilation,BUILD_CORBA, \
org/omg/PortableInterceptor/UNKNOWN.java \
com/sun/tools/corba/se/idl/ResourceBundleUtil.java \
com/sun/corba/se/impl/presentation/rmi/jndi.properties, \
- COPY := .prp LogStrings.properties, \
+ COPY := .prp, \
+ CLEAN := .properties, \
BIN := $(CORBA_OUTPUTDIR)/classes, \
JAR := $(CORBA_OUTPUTDIR)/dist/lib/classes.jar))
+# For the interim version, don't bother cleaning the properties.
$(eval $(call SetupJavaCompilation,BUILD_INTERIM_CORBA, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := $(BUILD_CORBA_SRC), \
EXCLUDES := $(BUILD_CORBA_EXCLUDES), \
EXCLUDE_FILES := $(BUILD_CORBA_EXCLUDE_FILES), \
- COPY := $(BUILD_CORBA_COPY), \
+ COPY := $(BUILD_CORBA_COPY) $(BUILD_CORBA_CLEAN), \
BIN := $(CORBA_OUTPUTDIR)/interim_classes, \
JAR := $(INTERIM_CORBA_JAR)))
@@ -63,7 +65,6 @@ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_CORBA, \
$(eval $(call SetupZipArchive,ARCHIVE_CORBA_SRC, \
SRC := $(CORBA_TOPDIR)/src/share/classes $(CORBA_OUTPUTDIR)/gensrc, \
ZIP := $(CORBA_OUTPUTDIR)/dist/lib/src.zip))
- JAR := $(CORBA_OUTPUTDIR)/dist/lib/classes.jar))
################################################################################
# Create bin.zip containing the corba specific binaries: orb.idl, ir.idl
@@ -81,6 +82,5 @@ $(CORBA_OUTPUTDIR)/dist/lib/bin.zip: $(BIN_FILES)
################################################################################
-
all: $(BUILD_CORBA) $(BUILD_INTERIM_CORBA) $(ARCHIVE_CORBA_SRC) \
$(CORBA_OUTPUTDIR)/dist/lib/bin.zip
diff --git a/corba/make/GensrcCorba.gmk b/corba/make/GensrcCorba.gmk
index 8dbf5102eda..4d078a56bb2 100644
--- a/corba/make/GensrcCorba.gmk
+++ b/corba/make/GensrcCorba.gmk
@@ -39,9 +39,6 @@ $(eval $(call SetupJavaCompilation,BUILD_TOOLS, \
SRC := $(CORBA_TOPDIR)/make/src/classes, \
BIN := $(CORBA_OUTPUTDIR)/tools_classes))
-TOOL_STRIPPROP_CMD := $(JAVA) -cp $(CORBA_OUTPUTDIR)/tools_classes \
- build.tools.stripproperties.StripPropertiesCorba
-
TOOL_LOGUTIL_CMD := $(JAVA) -cp $(CORBA_OUTPUTDIR)/tools_classes \
build.tools.logutil.MC
@@ -230,27 +227,14 @@ $(eval $(call SetupIdlCompilation,BUILD_IDLS, \
$(BUILD_IDLS): $(BUILD_IDLJ)
################################################################################
-# Run stripproperties on all sunorb resource files.
+# zh_HK is just a copy of zh_TW
-STRIP_PROP_SRC_FILES := $(shell $(FIND) $(CORBA_TOPDIR)/src/share/classes -name "sunorb*.properties")
-STRIP_PROP_FILES := $(patsubst $(CORBA_TOPDIR)/src/share/classes/%, $(CORBA_OUTPUTDIR)/classes/%, \
- $(STRIP_PROP_SRC_FILES))
-# Simple delivery of zh_HK properties files just copies zh_TW properties files
-STRIP_PROP_SRC_FILE_ZH_TW := $(shell $(FIND) $(CORBA_TOPDIR)/src/share/classes -name "sunorb_zh_TW.properties")
-STRIP_PROP_SRC_FILES += $(STRIP_PROP_SRC_FILE_ZH_TW)
-STRIP_PROP_FILES += $(patsubst $(CORBA_TOPDIR)/src/share/classes/%_zh_TW.properties, \
- $(CORBA_OUTPUTDIR)/classes/%_zh_HK.properties, $(STRIP_PROP_SRC_FILE_ZH_TW))
-STRIP_PROP_CMDLINE := $(subst _SPACE_, $(SPACE), \
- $(join $(addprefix -clean_SPACE_, $(STRIP_PROP_SRC_FILES)), \
- $(addprefix _SPACE_, $(STRIP_PROP_FILES))))
-
-$(CORBA_OUTPUTDIR)/_the.stripped_properties: $(STRIP_PROP_SRC_FILES) \
- $(BUILD_TOOLS)
- $(MKDIR) -p $(sort $(dir $(STRIP_PROP_FILES)))
- $(call ListPathsSafely,STRIP_PROP_CMDLINE,\n, >> $(CORBA_OUTPUTDIR)/_the.strip_prop.cmdline)
- $(TOOL_STRIPPROP_CMD) @$(CORBA_OUTPUTDIR)/_the.strip_prop.cmdline
- $(TOUCH) $@
+$(CORBA_OUTPUTDIR)/gensrc/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_HK.properties: \
+ $(CORBA_TOPDIR)/src/share/classes/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_TW.properties
+ $(install-file)
################################################################################
-all: $(BUILD_IDLS) $(CORBA_OUTPUTDIR)/_the.stripped_properties $(LOGWRAPPER_TARGETS)
+all: $(BUILD_IDLS) $(LOGWRAPPER_TARGETS) \
+ $(CORBA_OUTPUTDIR)/gensrc/com/sun/corba/se/impl/orbutil/resources/sunorb_zh_HK.properties
+
diff --git a/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java b/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java
deleted file mode 100644
index b5c7ecb253b..00000000000
--- a/corba/make/src/classes/build/tools/stripproperties/StripPropertiesCorba.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package build.tools.stripproperties;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Reads a properties file from standard input and writes an equivalent
- * properties file without comments to standard output.
- */
-public class StripPropertiesCorba {
-
- private static void error(String msg, Exception e) {
- System.err.println("ERROR: stripproperties: " + msg);
- if ( e != null ) {
- System.err.println("EXCEPTION: " + e.toString());
- e.printStackTrace();
- }
- }
-
- private static List infiles = new ArrayList();
- private static List outfiles = new ArrayList();
-
- private static boolean parseOptions(String args[]) {
- boolean ok = true;
-
- for ( int i = 0; i < args.length ; i++ ) {
- if ( "-clean".equals(args[i]) && i+2 < args.length ) {
- infiles.add(args[++i]);
- outfiles.add(args[++i]);
- } else if ( args[i].charAt(0)=='@') {
- String filename = args[i].substring(1);
- FileInputStream finput = null;
- byte contents[] = null;
- try {
- finput = new FileInputStream(filename);
- int byteCount = finput.available();
- if ( byteCount <= 0 ) {
- error("The @file is empty", null);
- ok = false;
- } else {
- contents = new byte[byteCount];
- int bytesRead = finput.read(contents);
- if ( byteCount != bytesRead ) {
- error("Cannot read all of @file", null);
- ok = false;
- }
- }
- } catch ( IOException e ) {
- error("cannot open " + filename, e);
- ok = false;
- }
- if ( finput != null ) {
- try {
- finput.close();
- } catch ( IOException e ) {
- ok = false;
- error("cannot close " + filename, e);
- }
- }
- if ( ok && contents != null ) {
- String tokens[] = (new String(contents)).split("\\s+");
- if ( tokens.length > 0 ) {
- ok = parseOptions(tokens);
- }
- }
- if ( !ok ) {
- break;
- }
- } else {
- infiles.add(args[i]);
- outfiles.add(args[i]);
- }
- }
- return ok;
- }
-
- private static boolean stripFiles(List infiles, List outfiles) {
- boolean ok = true;
- Iterator inIter = infiles.iterator();
- Iterator outIter = outfiles.iterator();
-
- for (; inIter.hasNext(); ) {
- String infile = inIter.next();
- String outfile = outIter.next();
-
- Properties prop = new Properties();
- InputStream in = null;
- try {
- in = new BufferedInputStream(new FileInputStream(infile));
- prop.load(in);
- } catch ( FileNotFoundException e ) {
- error("Cannot access file " + infile, e);
- ok = false;
- } catch ( IOException e ) {
- error("IO exception processing file " + infile, e);
- ok = false;
- }
- if ( in != null ) {
- try {
- in.close();
- } catch ( IOException e ) {
- error("IO exception closing file " + infile, e);
- ok = false;
- }
- }
- if ( !ok ) {
- break;
- }
-
- OutputStream out = null;
- try {
- out = new FileOutputStream(outfile);
- storeProperties(prop, out);
- out.flush();
- } catch ( IOException e ) {
- error("IO exception processing file " + outfile, e);
- ok = false;
- }
- if ( out != null ) {
- try {
- out.close();
- } catch ( IOException e ) {
- error("IO exception closing file " + outfile, e);
- ok = false;
- }
- }
- if ( !ok ) {
- break;
- }
-
- }
- return ok;
- }
-
- /**
- * Strip the properties filenames supplied, replacing their contents.
- * @param args Names of properties files to process and replace contents
- */
- public static void main(String args[]) {
- boolean ok = parseOptions(args);
- if ( !ok || !stripFiles(infiles, outfiles) ) {
- System.exit(1);
- }
- }
-
- // --- code below here is adapted from java.util.Properties ---
-
- private static final String specialSaveChars = "=: \t\r\n\f#!";
-
- /*
- * Converts unicodes to encoded \uxxxx
- * and writes out any of the characters in specialSaveChars
- * with a preceding slash
- */
- private static String saveConvert(String theString, boolean escapeSpace) {
- int len = theString.length();
- StringBuffer outBuffer = new StringBuffer(len*2);
-
- for(int x=0; x 0x00ff)) {
- outBuffer.append('\\');
- outBuffer.append('u');
- outBuffer.append(toHex((aChar >> 12) & 0xF));
- outBuffer.append(toHex((aChar >> 8) & 0xF));
- outBuffer.append(toHex((aChar >> 4) & 0xF));
- outBuffer.append(toHex( aChar & 0xF));
- } else {
- if (specialSaveChars.indexOf(aChar) != -1) {
- outBuffer.append('\\');
- }
- outBuffer.append(aChar);
- }
- }
- }
- return outBuffer.toString();
- }
-
- /**
- * Writes the content of properties to out.
- * The format is that of Properties.store with the following modifications:
- *
- * No header or date is written
- * Latin-1 characters are written as single bytes, not escape sequences
- * Line breaks are indicated by a single \n independent of platform
- *
- */
- private static void storeProperties(Properties properties, OutputStream out)
- throws IOException {
- BufferedWriter awriter;
- awriter = new BufferedWriter(new OutputStreamWriter(out, "8859_1"));
- for (Enumeration e = properties.keys(); e.hasMoreElements();) {
- String key = (String)e.nextElement();
- String val = (String)properties.get(key);
- key = saveConvert(key, true);
-
- /* No need to escape embedded and trailing spaces for value, hence
- * pass false to flag.
- */
- val = saveConvert(val, false);
- writeln(awriter, key + "=" + val);
- }
- awriter.flush();
- }
-
- private static void writeln(BufferedWriter bw, String s) throws IOException {
- bw.write(s);
- bw.write("\n");
- }
-
- /**
- * Convert a nibble to a hex character
- * @param nibble the nibble to convert.
- */
- private static char toHex(int nibble) {
- return hexDigit[(nibble & 0xF)];
- }
-
- /** A table of hex digits */
- private static final char[] hexDigit = {
- '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
- };
-}
From e5fb7f77d601805527b8c79c26e63643bb6fa305 Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Fri, 7 Mar 2014 13:30:23 -0800
Subject: [PATCH 046/116] 8036842: Remove unneeded/obsolete -source/-target
options in javac tests, part 2
Reviewed-by: jjg, sogoel
---
.../test/tools/javac/6464451/BigFinally.java | 245 --
.../javac/6464451/DeepNestedFinally.java | 76 -
.../tools/javac/6464451/ManyExitsInTry.java | 2051 -----------------
.../test/tools/javac/ArrayCloneCodeGen.java | 43 -
langtools/test/tools/javac/ClassLit.java | 5 +-
.../tools/javac/ConditionalArgTypes_2.java | 3 +-
.../test/tools/javac/ConditionalClass.java | 49 -
langtools/test/tools/javac/JsrRet.java | 2 +-
.../javac/NoNoClassDefFoundErrorError.java | 36 -
langtools/test/tools/javac/T6266772.java | 5 +-
langtools/test/tools/javac/T6557865.java | 45 -
.../javac/UplevelFromAnonInSuperCall.java | 1 -
.../test/tools/javac/annotations/neg/Dep.java | 1 -
.../javac/annotations/neg/MixedSource.java | 35 -
.../classfile/ClassfileTestHelper.java | 4 +-
.../classfile/NoTargetAnnotations.java | 4 +-
.../referenceinfos/Driver.java | 1 -
langtools/test/tools/javac/api/T6265137.java | 2 +-
.../test/tools/javac/boxing/NoBoxingBool.java | 34 -
.../test/tools/javac/boxing/NoBoxingByte.java | 34 -
.../test/tools/javac/boxing/NoBoxingChar.java | 34 -
.../tools/javac/boxing/NoBoxingDouble.java | 34 -
.../tools/javac/boxing/NoBoxingFloat.java | 34 -
.../test/tools/javac/boxing/NoBoxingInt.java | 34 -
.../test/tools/javac/boxing/NoBoxingLong.java | 34 -
.../tools/javac/boxing/NoBoxingShort.java | 34 -
.../javac/classfiles/ClassVersionChecker.java | 18 +-
.../tools/javac/enum/6384542/T6384542.java | 24 -
.../tools/javac/enum/6384542/T6384542.out | 9 -
.../tools/javac/enum/6384542/T6384542a.java | 14 -
.../javac/enum/6384542/T6384542a_1_4.out | 2 -
.../tools/javac/enum/6384542/T6384542a_5.out | 2 -
.../tools/javac/enum/EnumAsIdentifier.java | 2 -
.../tools/javac/enum/EnumAsIdentifier.out | 2 +-
.../tools/javac/enum/EnumAsIdentifier4.out | 6 -
.../tools/javac/enum/EnumAsIdentifier5.out | 6 -
.../test/tools/javac/enum/FauxEnum2.java | 37 -
.../test/tools/javac/foreach/T6682380.java | 45 -
.../tools/javac/generics/BridgeRestype.java | 42 -
.../test/tools/javac/generics/RefEqual.java | 3 +-
.../test/tools/javac/generics/T5094318.java | 4 +-
.../generics/compat/CovariantCompat1.java | 41 -
.../generics/compat/CovariantCompat2.java | 29 -
.../generics/compat/OverrideBridge1.java | 50 -
.../generics/compat/OverrideBridge2.java | 28 -
.../generics/compat/OverrideBridge3.java | 27 -
.../javac/generics/compat/VisibleBridge.java | 41 -
.../tools/javac/limits/FinallyNesting.java | 68 -
langtools/test/tools/javac/meth/InvokeMH.java | 4 +-
.../test/tools/javac/miranda/T4711325.java | 3 +-
.../tools/javac/proprietary/WarnClass.java | 3 +-
.../tools/javac/proprietary/WarnImport.java | 3 +-
.../tools/javac/proprietary/WarnMethod.java | 3 +-
.../javac/proprietary/WarnStaticImport.java | 3 +-
.../tools/javac/proprietary/WarnVariable.java | 3 +-
.../tools/javac/proprietary/WarnWildcard.java | 3 +-
.../types/CastObjectToPrimitiveTest.java | 1 -
.../javac/types/CastObjectToPrimitiveTest.out | 2 +-
58 files changed, 29 insertions(+), 3379 deletions(-)
delete mode 100644 langtools/test/tools/javac/6464451/BigFinally.java
delete mode 100644 langtools/test/tools/javac/6464451/DeepNestedFinally.java
delete mode 100644 langtools/test/tools/javac/6464451/ManyExitsInTry.java
delete mode 100644 langtools/test/tools/javac/ArrayCloneCodeGen.java
delete mode 100644 langtools/test/tools/javac/ConditionalClass.java
delete mode 100644 langtools/test/tools/javac/NoNoClassDefFoundErrorError.java
delete mode 100644 langtools/test/tools/javac/T6557865.java
delete mode 100644 langtools/test/tools/javac/annotations/neg/MixedSource.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingBool.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingByte.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingChar.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingDouble.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingFloat.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingInt.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingLong.java
delete mode 100644 langtools/test/tools/javac/boxing/NoBoxingShort.java
delete mode 100644 langtools/test/tools/javac/enum/6384542/T6384542.java
delete mode 100644 langtools/test/tools/javac/enum/6384542/T6384542.out
delete mode 100644 langtools/test/tools/javac/enum/6384542/T6384542a.java
delete mode 100644 langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out
delete mode 100644 langtools/test/tools/javac/enum/6384542/T6384542a_5.out
delete mode 100644 langtools/test/tools/javac/enum/EnumAsIdentifier4.out
delete mode 100644 langtools/test/tools/javac/enum/EnumAsIdentifier5.out
delete mode 100644 langtools/test/tools/javac/enum/FauxEnum2.java
delete mode 100644 langtools/test/tools/javac/foreach/T6682380.java
delete mode 100644 langtools/test/tools/javac/generics/BridgeRestype.java
delete mode 100644 langtools/test/tools/javac/generics/compat/CovariantCompat1.java
delete mode 100644 langtools/test/tools/javac/generics/compat/CovariantCompat2.java
delete mode 100644 langtools/test/tools/javac/generics/compat/OverrideBridge1.java
delete mode 100644 langtools/test/tools/javac/generics/compat/OverrideBridge2.java
delete mode 100644 langtools/test/tools/javac/generics/compat/OverrideBridge3.java
delete mode 100644 langtools/test/tools/javac/generics/compat/VisibleBridge.java
delete mode 100644 langtools/test/tools/javac/limits/FinallyNesting.java
diff --git a/langtools/test/tools/javac/6464451/BigFinally.java b/langtools/test/tools/javac/6464451/BigFinally.java
deleted file mode 100644
index 8f89e7d870f..00000000000
--- a/langtools/test/tools/javac/6464451/BigFinally.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 6464451
- * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return"
- * @author Wei Tao
- * @compile -source 5 -target 5 BigFinally.java
- * @clean BigFinally
- * @compile/fail BigFinally.java
- */
-
-public class BigFinally {
- static public int func(int i) {
- try {
- if(i == 1) return 1;
- } finally {
- try {
- if(i == 2) return 2;
- if(i == 3 ) return 3;
- if(i == 4 ) return 4;
- if(i == 5 ) return 5;
- if(i == 6 ) return 6;
- if(i == 7 ) return 7;
- if(i == 8 ) return 8;
- if(i == 9 ) return 9;
- if(i == 10 ) return 10;
- if(i == 11 ) return 11;
- if(i == 12 ) return 12;
- if(i == 13 ) return 13;
- if(i == 14 ) return 14;
- if(i == 15 ) return 15;
- if(i == 16 ) return 16;
- if(i == 17 ) return 17;
- if(i == 18 ) return 18;
- if(i == 19 ) return 19;
- if(i == 20 ) return 20;
- if(i == 21 ) return 21;
- if(i == 22 ) return 22;
- if(i == 23 ) return 23;
- if(i == 24 ) return 24;
- if(i == 25 ) return 25;
- if(i == 26 ) return 26;
- if(i == 27 ) return 27;
- if(i == 28 ) return 28;
- if(i == 29 ) return 29;
- if(i == 30 ) return 30;
- if(i == 31 ) return 31;
- if(i == 32 ) return 32;
- if(i == 33 ) return 33;
- if(i == 34 ) return 34;
- if(i == 35 ) return 35;
- if(i == 36 ) return 36;
- if(i == 37 ) return 37;
- if(i == 38 ) return 38;
- if(i == 39 ) return 39;
- if(i == 40 ) return 40;
- if(i == 41 ) return 41;
- if(i == 42 ) return 42;
- if(i == 43 ) return 43;
- if(i == 44 ) return 44;
- if(i == 45 ) return 45;
- if(i == 46 ) return 46;
- if(i == 47 ) return 47;
- if(i == 48 ) return 48;
- if(i == 49 ) return 49;
- if(i == 50 ) return 50;
- if(i == 51 ) return 51;
- if(i == 52 ) return 52;
- if(i == 53 ) return 53;
- if(i == 54 ) return 54;
- if(i == 55 ) return 55;
- if(i == 56 ) return 56;
- if(i == 57 ) return 57;
- if(i == 58 ) return 58;
- if(i == 59 ) return 59;
- if(i == 60 ) return 60;
- if(i == 61 ) return 61;
- if(i == 62 ) return 62;
- if(i == 63 ) return 63;
- if(i == 64 ) return 64;
- if(i == 65 ) return 65;
- if(i == 66 ) return 66;
- if(i == 67 ) return 67;
- if(i == 68 ) return 68;
- if(i == 69 ) return 69;
- if(i == 70 ) return 70;
- if(i == 71 ) return 71;
- if(i == 72 ) return 72;
- if(i == 73 ) return 73;
- if(i == 74 ) return 74;
- if(i == 75 ) return 75;
- if(i == 76 ) return 76;
- if(i == 77 ) return 77;
- if(i == 78 ) return 78;
- if(i == 79 ) return 79;
- if(i == 80 ) return 80;
- if(i == 81 ) return 81;
- if(i == 82 ) return 82;
- if(i == 83 ) return 83;
- if(i == 84 ) return 84;
- if(i == 85 ) return 85;
- if(i == 86 ) return 86;
- if(i == 87 ) return 87;
- if(i == 88 ) return 88;
- if(i == 89 ) return 89;
- if(i == 90 ) return 90;
- if(i == 91 ) return 91;
- if(i == 92 ) return 92;
- if(i == 93 ) return 93;
- if(i == 94 ) return 94;
- if(i == 95 ) return 95;
- if(i == 96 ) return 96;
- if(i == 97 ) return 97;
- if(i == 98 ) return 98;
- if(i == 99 ) return 99;
- if(i == 100 ) return 100;
- } finally {
- int x = 0;
- x += 1;
- x += 2;
- x += 3;
- x += 4;
- x += 5;
- x += 6;
- x += 7;
- x += 8;
- x += 9;
- x += 10;
- x += 11;
- x += 12;
- x += 13;
- x += 14;
- x += 15;
- x += 16;
- x += 17;
- x += 18;
- x += 19;
- x += 20;
- x += 21;
- x += 22;
- x += 23;
- x += 24;
- x += 25;
- x += 26;
- x += 27;
- x += 28;
- x += 29;
- x += 30;
- x += 31;
- x += 32;
- x += 33;
- x += 34;
- x += 35;
- x += 36;
- x += 37;
- x += 38;
- x += 39;
- x += 40;
- x += 41;
- x += 42;
- x += 43;
- x += 44;
- x += 45;
- x += 46;
- x += 47;
- x += 48;
- x += 49;
- x += 50;
- x += 51;
- x += 52;
- x += 53;
- x += 54;
- x += 55;
- x += 56;
- x += 57;
- x += 58;
- x += 59;
- x += 60;
- x += 61;
- x += 62;
- x += 63;
- x += 64;
- x += 65;
- x += 66;
- x += 67;
- x += 68;
- x += 69;
- x += 70;
- x += 71;
- x += 72;
- x += 73;
- x += 74;
- x += 75;
- x += 76;
- x += 77;
- x += 78;
- x += 79;
- x += 80;
- x += 81;
- x += 82;
- x += 83;
- x += 84;
- x += 85;
- x += 86;
- x += 87;
- x += 88;
- x += 89;
- x += 90;
- x += 91;
- x += 92;
- x += 93;
- x += 94;
- x += 95;
- x += 96;
- x += 97;
- x += 98;
- x += 99;
- x += 100;
- }
- }
- return 0;
- }
-}
diff --git a/langtools/test/tools/javac/6464451/DeepNestedFinally.java b/langtools/test/tools/javac/6464451/DeepNestedFinally.java
deleted file mode 100644
index fc6253cd975..00000000000
--- a/langtools/test/tools/javac/6464451/DeepNestedFinally.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 6464451
- * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return"
- * @author Wei Tao
- * @compile -source 5 -target 5 DeepNestedFinally.java
- * @clean DeepNestedFinally
- * @compile/fail DeepNestedFinally.java
- */
-
-public class DeepNestedFinally {
- static public int func(int i) {
- try {
- if(i == 1) return 1;
- } finally {
- try {
- if(i == 2) return 2;
- } finally {
- try {
- if(i == 3) return 3;
- } finally {
- try {
- if(i == 4) return 4;
- } finally {
- try {
- if(i == 5) return 5;
- } finally {
- try {
- if(i == 6) return 6;
- } finally {
- try {
- if (i == 7) return 7;
- } finally {
- int x = 0;
- x += 1;
- x += 2;
- x += 3;
- x += 4;
- x += 5;
- x += 6;
- x += 7;
- x += 8;
- x += 9;
- }
- }
- }
- }
- }
- }
- }
- return 0;
- }
-}
diff --git a/langtools/test/tools/javac/6464451/ManyExitsInTry.java b/langtools/test/tools/javac/6464451/ManyExitsInTry.java
deleted file mode 100644
index 95eb2ffadef..00000000000
--- a/langtools/test/tools/javac/6464451/ManyExitsInTry.java
+++ /dev/null
@@ -1,2051 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 6464451
- * @summary javac in 5.0ux can not compile try-finally block which has a lot of "return"
- * @author Wei Tao
- * @compile -source 5 -target 5 ManyExitsInTry.java
- * @clean ManyExitsInTry
- * @compile/fail ManyExitsInTry.java
- */
-
-public class ManyExitsInTry {
- static public int func(int i) {
- try {
- if(i == 0 ) return 0;
- if(i == 1 ) return 1;
- if(i == 2 ) return 2;
- if(i == 3 ) return 3;
- if(i == 4 ) return 4;
- if(i == 5 ) return 5;
- if(i == 6 ) return 6;
- if(i == 7 ) return 7;
- if(i == 8 ) return 8;
- if(i == 9 ) return 9;
- if(i == 10 ) return 10;
- if(i == 11 ) return 11;
- if(i == 12 ) return 12;
- if(i == 13 ) return 13;
- if(i == 14 ) return 14;
- if(i == 15 ) return 15;
- if(i == 16 ) return 16;
- if(i == 17 ) return 17;
- if(i == 18 ) return 18;
- if(i == 19 ) return 19;
- if(i == 20 ) return 20;
- if(i == 21 ) return 21;
- if(i == 22 ) return 22;
- if(i == 23 ) return 23;
- if(i == 24 ) return 24;
- if(i == 25 ) return 25;
- if(i == 26 ) return 26;
- if(i == 27 ) return 27;
- if(i == 28 ) return 28;
- if(i == 29 ) return 29;
- if(i == 30 ) return 30;
- if(i == 31 ) return 31;
- if(i == 32 ) return 32;
- if(i == 33 ) return 33;
- if(i == 34 ) return 34;
- if(i == 35 ) return 35;
- if(i == 36 ) return 36;
- if(i == 37 ) return 37;
- if(i == 38 ) return 38;
- if(i == 39 ) return 39;
- if(i == 40 ) return 40;
- if(i == 41 ) return 41;
- if(i == 42 ) return 42;
- if(i == 43 ) return 43;
- if(i == 44 ) return 44;
- if(i == 45 ) return 45;
- if(i == 46 ) return 46;
- if(i == 47 ) return 47;
- if(i == 48 ) return 48;
- if(i == 49 ) return 49;
- if(i == 50 ) return 50;
- if(i == 51 ) return 51;
- if(i == 52 ) return 52;
- if(i == 53 ) return 53;
- if(i == 54 ) return 54;
- if(i == 55 ) return 55;
- if(i == 56 ) return 56;
- if(i == 57 ) return 57;
- if(i == 58 ) return 58;
- if(i == 59 ) return 59;
- if(i == 60 ) return 60;
- if(i == 61 ) return 61;
- if(i == 62 ) return 62;
- if(i == 63 ) return 63;
- if(i == 64 ) return 64;
- if(i == 65 ) return 65;
- if(i == 66 ) return 66;
- if(i == 67 ) return 67;
- if(i == 68 ) return 68;
- if(i == 69 ) return 69;
- if(i == 70 ) return 70;
- if(i == 71 ) return 71;
- if(i == 72 ) return 72;
- if(i == 73 ) return 73;
- if(i == 74 ) return 74;
- if(i == 75 ) return 75;
- if(i == 76 ) return 76;
- if(i == 77 ) return 77;
- if(i == 78 ) return 78;
- if(i == 79 ) return 79;
- if(i == 80 ) return 80;
- if(i == 81 ) return 81;
- if(i == 82 ) return 82;
- if(i == 83 ) return 83;
- if(i == 84 ) return 84;
- if(i == 85 ) return 85;
- if(i == 86 ) return 86;
- if(i == 87 ) return 87;
- if(i == 88 ) return 88;
- if(i == 89 ) return 89;
- if(i == 90 ) return 90;
- if(i == 91 ) return 91;
- if(i == 92 ) return 92;
- if(i == 93 ) return 93;
- if(i == 94 ) return 94;
- if(i == 95 ) return 95;
- if(i == 96 ) return 96;
- if(i == 97 ) return 97;
- if(i == 98 ) return 98;
- if(i == 99 ) return 99;
- if(i == 100 ) return 100;
- if(i == 101 ) return 101;
- if(i == 102 ) return 102;
- if(i == 103 ) return 103;
- if(i == 104 ) return 104;
- if(i == 105 ) return 105;
- if(i == 106 ) return 106;
- if(i == 107 ) return 107;
- if(i == 108 ) return 108;
- if(i == 109 ) return 109;
- if(i == 110 ) return 110;
- if(i == 111 ) return 111;
- if(i == 112 ) return 112;
- if(i == 113 ) return 113;
- if(i == 114 ) return 114;
- if(i == 115 ) return 115;
- if(i == 116 ) return 116;
- if(i == 117 ) return 117;
- if(i == 118 ) return 118;
- if(i == 119 ) return 119;
- if(i == 120 ) return 120;
- if(i == 121 ) return 121;
- if(i == 122 ) return 122;
- if(i == 123 ) return 123;
- if(i == 124 ) return 124;
- if(i == 125 ) return 125;
- if(i == 126 ) return 126;
- if(i == 127 ) return 127;
- if(i == 128 ) return 128;
- if(i == 129 ) return 129;
- if(i == 130 ) return 130;
- if(i == 131 ) return 131;
- if(i == 132 ) return 132;
- if(i == 133 ) return 133;
- if(i == 134 ) return 134;
- if(i == 135 ) return 135;
- if(i == 136 ) return 136;
- if(i == 137 ) return 137;
- if(i == 138 ) return 138;
- if(i == 139 ) return 139;
- if(i == 140 ) return 140;
- if(i == 141 ) return 141;
- if(i == 142 ) return 142;
- if(i == 143 ) return 143;
- if(i == 144 ) return 144;
- if(i == 145 ) return 145;
- if(i == 146 ) return 146;
- if(i == 147 ) return 147;
- if(i == 148 ) return 148;
- if(i == 149 ) return 149;
- if(i == 150 ) return 150;
- if(i == 151 ) return 151;
- if(i == 152 ) return 152;
- if(i == 153 ) return 153;
- if(i == 154 ) return 154;
- if(i == 155 ) return 155;
- if(i == 156 ) return 156;
- if(i == 157 ) return 157;
- if(i == 158 ) return 158;
- if(i == 159 ) return 159;
- if(i == 160 ) return 160;
- if(i == 161 ) return 161;
- if(i == 162 ) return 162;
- if(i == 163 ) return 163;
- if(i == 164 ) return 164;
- if(i == 165 ) return 165;
- if(i == 166 ) return 166;
- if(i == 167 ) return 167;
- if(i == 168 ) return 168;
- if(i == 169 ) return 169;
- if(i == 170 ) return 170;
- if(i == 171 ) return 171;
- if(i == 172 ) return 172;
- if(i == 173 ) return 173;
- if(i == 174 ) return 174;
- if(i == 175 ) return 175;
- if(i == 176 ) return 176;
- if(i == 177 ) return 177;
- if(i == 178 ) return 178;
- if(i == 179 ) return 179;
- if(i == 180 ) return 180;
- if(i == 181 ) return 181;
- if(i == 182 ) return 182;
- if(i == 183 ) return 183;
- if(i == 184 ) return 184;
- if(i == 185 ) return 185;
- if(i == 186 ) return 186;
- if(i == 187 ) return 187;
- if(i == 188 ) return 188;
- if(i == 189 ) return 189;
- if(i == 190 ) return 190;
- if(i == 191 ) return 191;
- if(i == 192 ) return 192;
- if(i == 193 ) return 193;
- if(i == 194 ) return 194;
- if(i == 195 ) return 195;
- if(i == 196 ) return 196;
- if(i == 197 ) return 197;
- if(i == 198 ) return 198;
- if(i == 199 ) return 199;
- if(i == 200 ) return 200;
- if(i == 201 ) return 201;
- if(i == 202 ) return 202;
- if(i == 203 ) return 203;
- if(i == 204 ) return 204;
- if(i == 205 ) return 205;
- if(i == 206 ) return 206;
- if(i == 207 ) return 207;
- if(i == 208 ) return 208;
- if(i == 209 ) return 209;
- if(i == 210 ) return 210;
- if(i == 211 ) return 211;
- if(i == 212 ) return 212;
- if(i == 213 ) return 213;
- if(i == 214 ) return 214;
- if(i == 215 ) return 215;
- if(i == 216 ) return 216;
- if(i == 217 ) return 217;
- if(i == 218 ) return 218;
- if(i == 219 ) return 219;
- if(i == 220 ) return 220;
- if(i == 221 ) return 221;
- if(i == 222 ) return 222;
- if(i == 223 ) return 223;
- if(i == 224 ) return 224;
- if(i == 225 ) return 225;
- if(i == 226 ) return 226;
- if(i == 227 ) return 227;
- if(i == 228 ) return 228;
- if(i == 229 ) return 229;
- if(i == 230 ) return 230;
- if(i == 231 ) return 231;
- if(i == 232 ) return 232;
- if(i == 233 ) return 233;
- if(i == 234 ) return 234;
- if(i == 235 ) return 235;
- if(i == 236 ) return 236;
- if(i == 237 ) return 237;
- if(i == 238 ) return 238;
- if(i == 239 ) return 239;
- if(i == 240 ) return 240;
- if(i == 241 ) return 241;
- if(i == 242 ) return 242;
- if(i == 243 ) return 243;
- if(i == 244 ) return 244;
- if(i == 245 ) return 245;
- if(i == 246 ) return 246;
- if(i == 247 ) return 247;
- if(i == 248 ) return 248;
- if(i == 249 ) return 249;
- if(i == 250 ) return 250;
- if(i == 251 ) return 251;
- if(i == 252 ) return 252;
- if(i == 253 ) return 253;
- if(i == 254 ) return 254;
- if(i == 255 ) return 255;
- if(i == 256 ) return 256;
- if(i == 257 ) return 257;
- if(i == 258 ) return 258;
- if(i == 259 ) return 259;
- if(i == 260 ) return 260;
- if(i == 261 ) return 261;
- if(i == 262 ) return 262;
- if(i == 263 ) return 263;
- if(i == 264 ) return 264;
- if(i == 265 ) return 265;
- if(i == 266 ) return 266;
- if(i == 267 ) return 267;
- if(i == 268 ) return 268;
- if(i == 269 ) return 269;
- if(i == 270 ) return 270;
- if(i == 271 ) return 271;
- if(i == 272 ) return 272;
- if(i == 273 ) return 273;
- if(i == 274 ) return 274;
- if(i == 275 ) return 275;
- if(i == 276 ) return 276;
- if(i == 277 ) return 277;
- if(i == 278 ) return 278;
- if(i == 279 ) return 279;
- if(i == 280 ) return 280;
- if(i == 281 ) return 281;
- if(i == 282 ) return 282;
- if(i == 283 ) return 283;
- if(i == 284 ) return 284;
- if(i == 285 ) return 285;
- if(i == 286 ) return 286;
- if(i == 287 ) return 287;
- if(i == 288 ) return 288;
- if(i == 289 ) return 289;
- if(i == 290 ) return 290;
- if(i == 291 ) return 291;
- if(i == 292 ) return 292;
- if(i == 293 ) return 293;
- if(i == 294 ) return 294;
- if(i == 295 ) return 295;
- if(i == 296 ) return 296;
- if(i == 297 ) return 297;
- if(i == 298 ) return 298;
- if(i == 299 ) return 299;
- if(i == 300 ) return 300;
- if(i == 301 ) return 301;
- if(i == 302 ) return 302;
- if(i == 303 ) return 303;
- if(i == 304 ) return 304;
- if(i == 305 ) return 305;
- if(i == 306 ) return 306;
- if(i == 307 ) return 307;
- if(i == 308 ) return 308;
- if(i == 309 ) return 309;
- if(i == 310 ) return 310;
- if(i == 311 ) return 311;
- if(i == 312 ) return 312;
- if(i == 313 ) return 313;
- if(i == 314 ) return 314;
- if(i == 315 ) return 315;
- if(i == 316 ) return 316;
- if(i == 317 ) return 317;
- if(i == 318 ) return 318;
- if(i == 319 ) return 319;
- if(i == 320 ) return 320;
- if(i == 321 ) return 321;
- if(i == 322 ) return 322;
- if(i == 323 ) return 323;
- if(i == 324 ) return 324;
- if(i == 325 ) return 325;
- if(i == 326 ) return 326;
- if(i == 327 ) return 327;
- if(i == 328 ) return 328;
- if(i == 329 ) return 329;
- if(i == 330 ) return 330;
- if(i == 331 ) return 331;
- if(i == 332 ) return 332;
- if(i == 333 ) return 333;
- if(i == 334 ) return 334;
- if(i == 335 ) return 335;
- if(i == 336 ) return 336;
- if(i == 337 ) return 337;
- if(i == 338 ) return 338;
- if(i == 339 ) return 339;
- if(i == 340 ) return 340;
- if(i == 341 ) return 341;
- if(i == 342 ) return 342;
- if(i == 343 ) return 343;
- if(i == 344 ) return 344;
- if(i == 345 ) return 345;
- if(i == 346 ) return 346;
- if(i == 347 ) return 347;
- if(i == 348 ) return 348;
- if(i == 349 ) return 349;
- if(i == 350 ) return 350;
- if(i == 351 ) return 351;
- if(i == 352 ) return 352;
- if(i == 353 ) return 353;
- if(i == 354 ) return 354;
- if(i == 355 ) return 355;
- if(i == 356 ) return 356;
- if(i == 357 ) return 357;
- if(i == 358 ) return 358;
- if(i == 359 ) return 359;
- if(i == 360 ) return 360;
- if(i == 361 ) return 361;
- if(i == 362 ) return 362;
- if(i == 363 ) return 363;
- if(i == 364 ) return 364;
- if(i == 365 ) return 365;
- if(i == 366 ) return 366;
- if(i == 367 ) return 367;
- if(i == 368 ) return 368;
- if(i == 369 ) return 369;
- if(i == 370 ) return 370;
- if(i == 371 ) return 371;
- if(i == 372 ) return 372;
- if(i == 373 ) return 373;
- if(i == 374 ) return 374;
- if(i == 375 ) return 375;
- if(i == 376 ) return 376;
- if(i == 377 ) return 377;
- if(i == 378 ) return 378;
- if(i == 379 ) return 379;
- if(i == 380 ) return 380;
- if(i == 381 ) return 381;
- if(i == 382 ) return 382;
- if(i == 383 ) return 383;
- if(i == 384 ) return 384;
- if(i == 385 ) return 385;
- if(i == 386 ) return 386;
- if(i == 387 ) return 387;
- if(i == 388 ) return 388;
- if(i == 389 ) return 389;
- if(i == 390 ) return 390;
- if(i == 391 ) return 391;
- if(i == 392 ) return 392;
- if(i == 393 ) return 393;
- if(i == 394 ) return 394;
- if(i == 395 ) return 395;
- if(i == 396 ) return 396;
- if(i == 397 ) return 397;
- if(i == 398 ) return 398;
- if(i == 399 ) return 399;
- if(i == 400 ) return 400;
- if(i == 401 ) return 401;
- if(i == 402 ) return 402;
- if(i == 403 ) return 403;
- if(i == 404 ) return 404;
- if(i == 405 ) return 405;
- if(i == 406 ) return 406;
- if(i == 407 ) return 407;
- if(i == 408 ) return 408;
- if(i == 409 ) return 409;
- if(i == 410 ) return 410;
- if(i == 411 ) return 411;
- if(i == 412 ) return 412;
- if(i == 413 ) return 413;
- if(i == 414 ) return 414;
- if(i == 415 ) return 415;
- if(i == 416 ) return 416;
- if(i == 417 ) return 417;
- if(i == 418 ) return 418;
- if(i == 419 ) return 419;
- if(i == 420 ) return 420;
- if(i == 421 ) return 421;
- if(i == 422 ) return 422;
- if(i == 423 ) return 423;
- if(i == 424 ) return 424;
- if(i == 425 ) return 425;
- if(i == 426 ) return 426;
- if(i == 427 ) return 427;
- if(i == 428 ) return 428;
- if(i == 429 ) return 429;
- if(i == 430 ) return 430;
- if(i == 431 ) return 431;
- if(i == 432 ) return 432;
- if(i == 433 ) return 433;
- if(i == 434 ) return 434;
- if(i == 435 ) return 435;
- if(i == 436 ) return 436;
- if(i == 437 ) return 437;
- if(i == 438 ) return 438;
- if(i == 439 ) return 439;
- if(i == 440 ) return 440;
- if(i == 441 ) return 441;
- if(i == 442 ) return 442;
- if(i == 443 ) return 443;
- if(i == 444 ) return 444;
- if(i == 445 ) return 445;
- if(i == 446 ) return 446;
- if(i == 447 ) return 447;
- if(i == 448 ) return 448;
- if(i == 449 ) return 449;
- if(i == 450 ) return 450;
- if(i == 451 ) return 451;
- if(i == 452 ) return 452;
- if(i == 453 ) return 453;
- if(i == 454 ) return 454;
- if(i == 455 ) return 455;
- if(i == 456 ) return 456;
- if(i == 457 ) return 457;
- if(i == 458 ) return 458;
- if(i == 459 ) return 459;
- if(i == 460 ) return 460;
- if(i == 461 ) return 461;
- if(i == 462 ) return 462;
- if(i == 463 ) return 463;
- if(i == 464 ) return 464;
- if(i == 465 ) return 465;
- if(i == 466 ) return 466;
- if(i == 467 ) return 467;
- if(i == 468 ) return 468;
- if(i == 469 ) return 469;
- if(i == 470 ) return 470;
- if(i == 471 ) return 471;
- if(i == 472 ) return 472;
- if(i == 473 ) return 473;
- if(i == 474 ) return 474;
- if(i == 475 ) return 475;
- if(i == 476 ) return 476;
- if(i == 477 ) return 477;
- if(i == 478 ) return 478;
- if(i == 479 ) return 479;
- if(i == 480 ) return 480;
- if(i == 481 ) return 481;
- if(i == 482 ) return 482;
- if(i == 483 ) return 483;
- if(i == 484 ) return 484;
- if(i == 485 ) return 485;
- if(i == 486 ) return 486;
- if(i == 487 ) return 487;
- if(i == 488 ) return 488;
- if(i == 489 ) return 489;
- if(i == 490 ) return 490;
- if(i == 491 ) return 491;
- if(i == 492 ) return 492;
- if(i == 493 ) return 493;
- if(i == 494 ) return 494;
- if(i == 495 ) return 495;
- if(i == 496 ) return 496;
- if(i == 497 ) return 497;
- if(i == 498 ) return 498;
- if(i == 499 ) return 499;
- if(i == 500 ) return 500;
- if(i == 501 ) return 501;
- if(i == 502 ) return 502;
- if(i == 503 ) return 503;
- if(i == 504 ) return 504;
- if(i == 505 ) return 505;
- if(i == 506 ) return 506;
- if(i == 507 ) return 507;
- if(i == 508 ) return 508;
- if(i == 509 ) return 509;
- if(i == 510 ) return 510;
- if(i == 511 ) return 511;
- if(i == 512 ) return 512;
- if(i == 513 ) return 513;
- if(i == 514 ) return 514;
- if(i == 515 ) return 515;
- if(i == 516 ) return 516;
- if(i == 517 ) return 517;
- if(i == 518 ) return 518;
- if(i == 519 ) return 519;
- if(i == 520 ) return 520;
- if(i == 521 ) return 521;
- if(i == 522 ) return 522;
- if(i == 523 ) return 523;
- if(i == 524 ) return 524;
- if(i == 525 ) return 525;
- if(i == 526 ) return 526;
- if(i == 527 ) return 527;
- if(i == 528 ) return 528;
- if(i == 529 ) return 529;
- if(i == 530 ) return 530;
- if(i == 531 ) return 531;
- if(i == 532 ) return 532;
- if(i == 533 ) return 533;
- if(i == 534 ) return 534;
- if(i == 535 ) return 535;
- if(i == 536 ) return 536;
- if(i == 537 ) return 537;
- if(i == 538 ) return 538;
- if(i == 539 ) return 539;
- if(i == 540 ) return 540;
- if(i == 541 ) return 541;
- if(i == 542 ) return 542;
- if(i == 543 ) return 543;
- if(i == 544 ) return 544;
- if(i == 545 ) return 545;
- if(i == 546 ) return 546;
- if(i == 547 ) return 547;
- if(i == 548 ) return 548;
- if(i == 549 ) return 549;
- if(i == 550 ) return 550;
- if(i == 551 ) return 551;
- if(i == 552 ) return 552;
- if(i == 553 ) return 553;
- if(i == 554 ) return 554;
- if(i == 555 ) return 555;
- if(i == 556 ) return 556;
- if(i == 557 ) return 557;
- if(i == 558 ) return 558;
- if(i == 559 ) return 559;
- if(i == 560 ) return 560;
- if(i == 561 ) return 561;
- if(i == 562 ) return 562;
- if(i == 563 ) return 563;
- if(i == 564 ) return 564;
- if(i == 565 ) return 565;
- if(i == 566 ) return 566;
- if(i == 567 ) return 567;
- if(i == 568 ) return 568;
- if(i == 569 ) return 569;
- if(i == 570 ) return 570;
- if(i == 571 ) return 571;
- if(i == 572 ) return 572;
- if(i == 573 ) return 573;
- if(i == 574 ) return 574;
- if(i == 575 ) return 575;
- if(i == 576 ) return 576;
- if(i == 577 ) return 577;
- if(i == 578 ) return 578;
- if(i == 579 ) return 579;
- if(i == 580 ) return 580;
- if(i == 581 ) return 581;
- if(i == 582 ) return 582;
- if(i == 583 ) return 583;
- if(i == 584 ) return 584;
- if(i == 585 ) return 585;
- if(i == 586 ) return 586;
- if(i == 587 ) return 587;
- if(i == 588 ) return 588;
- if(i == 589 ) return 589;
- if(i == 590 ) return 590;
- if(i == 591 ) return 591;
- if(i == 592 ) return 592;
- if(i == 593 ) return 593;
- if(i == 594 ) return 594;
- if(i == 595 ) return 595;
- if(i == 596 ) return 596;
- if(i == 597 ) return 597;
- if(i == 598 ) return 598;
- if(i == 599 ) return 599;
- if(i == 600 ) return 600;
- if(i == 601 ) return 601;
- if(i == 602 ) return 602;
- if(i == 603 ) return 603;
- if(i == 604 ) return 604;
- if(i == 605 ) return 605;
- if(i == 606 ) return 606;
- if(i == 607 ) return 607;
- if(i == 608 ) return 608;
- if(i == 609 ) return 609;
- if(i == 610 ) return 610;
- if(i == 611 ) return 611;
- if(i == 612 ) return 612;
- if(i == 613 ) return 613;
- if(i == 614 ) return 614;
- if(i == 615 ) return 615;
- if(i == 616 ) return 616;
- if(i == 617 ) return 617;
- if(i == 618 ) return 618;
- if(i == 619 ) return 619;
- if(i == 620 ) return 620;
- if(i == 621 ) return 621;
- if(i == 622 ) return 622;
- if(i == 623 ) return 623;
- if(i == 624 ) return 624;
- if(i == 625 ) return 625;
- if(i == 626 ) return 626;
- if(i == 627 ) return 627;
- if(i == 628 ) return 628;
- if(i == 629 ) return 629;
- if(i == 630 ) return 630;
- if(i == 631 ) return 631;
- if(i == 632 ) return 632;
- if(i == 633 ) return 633;
- if(i == 634 ) return 634;
- if(i == 635 ) return 635;
- if(i == 636 ) return 636;
- if(i == 637 ) return 637;
- if(i == 638 ) return 638;
- if(i == 639 ) return 639;
- if(i == 640 ) return 640;
- if(i == 641 ) return 641;
- if(i == 642 ) return 642;
- if(i == 643 ) return 643;
- if(i == 644 ) return 644;
- if(i == 645 ) return 645;
- if(i == 646 ) return 646;
- if(i == 647 ) return 647;
- if(i == 648 ) return 648;
- if(i == 649 ) return 649;
- if(i == 650 ) return 650;
- if(i == 651 ) return 651;
- if(i == 652 ) return 652;
- if(i == 653 ) return 653;
- if(i == 654 ) return 654;
- if(i == 655 ) return 655;
- if(i == 656 ) return 656;
- if(i == 657 ) return 657;
- if(i == 658 ) return 658;
- if(i == 659 ) return 659;
- if(i == 660 ) return 660;
- if(i == 661 ) return 661;
- if(i == 662 ) return 662;
- if(i == 663 ) return 663;
- if(i == 664 ) return 664;
- if(i == 665 ) return 665;
- if(i == 666 ) return 666;
- if(i == 667 ) return 667;
- if(i == 668 ) return 668;
- if(i == 669 ) return 669;
- if(i == 670 ) return 670;
- if(i == 671 ) return 671;
- if(i == 672 ) return 672;
- if(i == 673 ) return 673;
- if(i == 674 ) return 674;
- if(i == 675 ) return 675;
- if(i == 676 ) return 676;
- if(i == 677 ) return 677;
- if(i == 678 ) return 678;
- if(i == 679 ) return 679;
- if(i == 680 ) return 680;
- if(i == 681 ) return 681;
- if(i == 682 ) return 682;
- if(i == 683 ) return 683;
- if(i == 684 ) return 684;
- if(i == 685 ) return 685;
- if(i == 686 ) return 686;
- if(i == 687 ) return 687;
- if(i == 688 ) return 688;
- if(i == 689 ) return 689;
- if(i == 690 ) return 690;
- if(i == 691 ) return 691;
- if(i == 692 ) return 692;
- if(i == 693 ) return 693;
- if(i == 694 ) return 694;
- if(i == 695 ) return 695;
- if(i == 696 ) return 696;
- if(i == 697 ) return 697;
- if(i == 698 ) return 698;
- if(i == 699 ) return 699;
- if(i == 700 ) return 700;
- if(i == 701 ) return 701;
- if(i == 702 ) return 702;
- if(i == 703 ) return 703;
- if(i == 704 ) return 704;
- if(i == 705 ) return 705;
- if(i == 706 ) return 706;
- if(i == 707 ) return 707;
- if(i == 708 ) return 708;
- if(i == 709 ) return 709;
- if(i == 710 ) return 710;
- if(i == 711 ) return 711;
- if(i == 712 ) return 712;
- if(i == 713 ) return 713;
- if(i == 714 ) return 714;
- if(i == 715 ) return 715;
- if(i == 716 ) return 716;
- if(i == 717 ) return 717;
- if(i == 718 ) return 718;
- if(i == 719 ) return 719;
- if(i == 720 ) return 720;
- if(i == 721 ) return 721;
- if(i == 722 ) return 722;
- if(i == 723 ) return 723;
- if(i == 724 ) return 724;
- if(i == 725 ) return 725;
- if(i == 726 ) return 726;
- if(i == 727 ) return 727;
- if(i == 728 ) return 728;
- if(i == 729 ) return 729;
- if(i == 730 ) return 730;
- if(i == 731 ) return 731;
- if(i == 732 ) return 732;
- if(i == 733 ) return 733;
- if(i == 734 ) return 734;
- if(i == 735 ) return 735;
- if(i == 736 ) return 736;
- if(i == 737 ) return 737;
- if(i == 738 ) return 738;
- if(i == 739 ) return 739;
- if(i == 740 ) return 740;
- if(i == 741 ) return 741;
- if(i == 742 ) return 742;
- if(i == 743 ) return 743;
- if(i == 744 ) return 744;
- if(i == 745 ) return 745;
- if(i == 746 ) return 746;
- if(i == 747 ) return 747;
- if(i == 748 ) return 748;
- if(i == 749 ) return 749;
- if(i == 750 ) return 750;
- if(i == 751 ) return 751;
- if(i == 752 ) return 752;
- if(i == 753 ) return 753;
- if(i == 754 ) return 754;
- if(i == 755 ) return 755;
- if(i == 756 ) return 756;
- if(i == 757 ) return 757;
- if(i == 758 ) return 758;
- if(i == 759 ) return 759;
- if(i == 760 ) return 760;
- if(i == 761 ) return 761;
- if(i == 762 ) return 762;
- if(i == 763 ) return 763;
- if(i == 764 ) return 764;
- if(i == 765 ) return 765;
- if(i == 766 ) return 766;
- if(i == 767 ) return 767;
- if(i == 768 ) return 768;
- if(i == 769 ) return 769;
- if(i == 770 ) return 770;
- if(i == 771 ) return 771;
- if(i == 772 ) return 772;
- if(i == 773 ) return 773;
- if(i == 774 ) return 774;
- if(i == 775 ) return 775;
- if(i == 776 ) return 776;
- if(i == 777 ) return 777;
- if(i == 778 ) return 778;
- if(i == 779 ) return 779;
- if(i == 780 ) return 780;
- if(i == 781 ) return 781;
- if(i == 782 ) return 782;
- if(i == 783 ) return 783;
- if(i == 784 ) return 784;
- if(i == 785 ) return 785;
- if(i == 786 ) return 786;
- if(i == 787 ) return 787;
- if(i == 788 ) return 788;
- if(i == 789 ) return 789;
- if(i == 790 ) return 790;
- if(i == 791 ) return 791;
- if(i == 792 ) return 792;
- if(i == 793 ) return 793;
- if(i == 794 ) return 794;
- if(i == 795 ) return 795;
- if(i == 796 ) return 796;
- if(i == 797 ) return 797;
- if(i == 798 ) return 798;
- if(i == 799 ) return 799;
- if(i == 800 ) return 800;
- if(i == 801 ) return 801;
- if(i == 802 ) return 802;
- if(i == 803 ) return 803;
- if(i == 804 ) return 804;
- if(i == 805 ) return 805;
- if(i == 806 ) return 806;
- if(i == 807 ) return 807;
- if(i == 808 ) return 808;
- if(i == 809 ) return 809;
- if(i == 810 ) return 810;
- if(i == 811 ) return 811;
- if(i == 812 ) return 812;
- if(i == 813 ) return 813;
- if(i == 814 ) return 814;
- if(i == 815 ) return 815;
- if(i == 816 ) return 816;
- if(i == 817 ) return 817;
- if(i == 818 ) return 818;
- if(i == 819 ) return 819;
- if(i == 820 ) return 820;
- if(i == 821 ) return 821;
- if(i == 822 ) return 822;
- if(i == 823 ) return 823;
- if(i == 824 ) return 824;
- if(i == 825 ) return 825;
- if(i == 826 ) return 826;
- if(i == 827 ) return 827;
- if(i == 828 ) return 828;
- if(i == 829 ) return 829;
- if(i == 830 ) return 830;
- if(i == 831 ) return 831;
- if(i == 832 ) return 832;
- if(i == 833 ) return 833;
- if(i == 834 ) return 834;
- if(i == 835 ) return 835;
- if(i == 836 ) return 836;
- if(i == 837 ) return 837;
- if(i == 838 ) return 838;
- if(i == 839 ) return 839;
- if(i == 840 ) return 840;
- if(i == 841 ) return 841;
- if(i == 842 ) return 842;
- if(i == 843 ) return 843;
- if(i == 844 ) return 844;
- if(i == 845 ) return 845;
- if(i == 846 ) return 846;
- if(i == 847 ) return 847;
- if(i == 848 ) return 848;
- if(i == 849 ) return 849;
- if(i == 850 ) return 850;
- if(i == 851 ) return 851;
- if(i == 852 ) return 852;
- if(i == 853 ) return 853;
- if(i == 854 ) return 854;
- if(i == 855 ) return 855;
- if(i == 856 ) return 856;
- if(i == 857 ) return 857;
- if(i == 858 ) return 858;
- if(i == 859 ) return 859;
- if(i == 860 ) return 860;
- if(i == 861 ) return 861;
- if(i == 862 ) return 862;
- if(i == 863 ) return 863;
- if(i == 864 ) return 864;
- if(i == 865 ) return 865;
- if(i == 866 ) return 866;
- if(i == 867 ) return 867;
- if(i == 868 ) return 868;
- if(i == 869 ) return 869;
- if(i == 870 ) return 870;
- if(i == 871 ) return 871;
- if(i == 872 ) return 872;
- if(i == 873 ) return 873;
- if(i == 874 ) return 874;
- if(i == 875 ) return 875;
- if(i == 876 ) return 876;
- if(i == 877 ) return 877;
- if(i == 878 ) return 878;
- if(i == 879 ) return 879;
- if(i == 880 ) return 880;
- if(i == 881 ) return 881;
- if(i == 882 ) return 882;
- if(i == 883 ) return 883;
- if(i == 884 ) return 884;
- if(i == 885 ) return 885;
- if(i == 886 ) return 886;
- if(i == 887 ) return 887;
- if(i == 888 ) return 888;
- if(i == 889 ) return 889;
- if(i == 890 ) return 890;
- if(i == 891 ) return 891;
- if(i == 892 ) return 892;
- if(i == 893 ) return 893;
- if(i == 894 ) return 894;
- if(i == 895 ) return 895;
- if(i == 896 ) return 896;
- if(i == 897 ) return 897;
- if(i == 898 ) return 898;
- if(i == 899 ) return 899;
- if(i == 900 ) return 900;
- if(i == 901 ) return 901;
- if(i == 902 ) return 902;
- if(i == 903 ) return 903;
- if(i == 904 ) return 904;
- if(i == 905 ) return 905;
- if(i == 906 ) return 906;
- if(i == 907 ) return 907;
- if(i == 908 ) return 908;
- if(i == 909 ) return 909;
- if(i == 910 ) return 910;
- if(i == 911 ) return 911;
- if(i == 912 ) return 912;
- if(i == 913 ) return 913;
- if(i == 914 ) return 914;
- if(i == 915 ) return 915;
- if(i == 916 ) return 916;
- if(i == 917 ) return 917;
- if(i == 918 ) return 918;
- if(i == 919 ) return 919;
- if(i == 920 ) return 920;
- if(i == 921 ) return 921;
- if(i == 922 ) return 922;
- if(i == 923 ) return 923;
- if(i == 924 ) return 924;
- if(i == 925 ) return 925;
- if(i == 926 ) return 926;
- if(i == 927 ) return 927;
- if(i == 928 ) return 928;
- if(i == 929 ) return 929;
- if(i == 930 ) return 930;
- if(i == 931 ) return 931;
- if(i == 932 ) return 932;
- if(i == 933 ) return 933;
- if(i == 934 ) return 934;
- if(i == 935 ) return 935;
- if(i == 936 ) return 936;
- if(i == 937 ) return 937;
- if(i == 938 ) return 938;
- if(i == 939 ) return 939;
- if(i == 940 ) return 940;
- if(i == 941 ) return 941;
- if(i == 942 ) return 942;
- if(i == 943 ) return 943;
- if(i == 944 ) return 944;
- if(i == 945 ) return 945;
- if(i == 946 ) return 946;
- if(i == 947 ) return 947;
- if(i == 948 ) return 948;
- if(i == 949 ) return 949;
- if(i == 950 ) return 950;
- if(i == 951 ) return 951;
- if(i == 952 ) return 952;
- if(i == 953 ) return 953;
- if(i == 954 ) return 954;
- if(i == 955 ) return 955;
- if(i == 956 ) return 956;
- if(i == 957 ) return 957;
- if(i == 958 ) return 958;
- if(i == 959 ) return 959;
- if(i == 960 ) return 960;
- if(i == 961 ) return 961;
- if(i == 962 ) return 962;
- if(i == 963 ) return 963;
- if(i == 964 ) return 964;
- if(i == 965 ) return 965;
- if(i == 966 ) return 966;
- if(i == 967 ) return 967;
- if(i == 968 ) return 968;
- if(i == 969 ) return 969;
- if(i == 970 ) return 970;
- if(i == 971 ) return 971;
- if(i == 972 ) return 972;
- if(i == 973 ) return 973;
- if(i == 974 ) return 974;
- if(i == 975 ) return 975;
- if(i == 976 ) return 976;
- if(i == 977 ) return 977;
- if(i == 978 ) return 978;
- if(i == 979 ) return 979;
- if(i == 980 ) return 980;
- if(i == 981 ) return 981;
- if(i == 982 ) return 982;
- if(i == 983 ) return 983;
- if(i == 984 ) return 984;
- if(i == 985 ) return 985;
- if(i == 986 ) return 986;
- if(i == 987 ) return 987;
- if(i == 988 ) return 988;
- if(i == 989 ) return 989;
- if(i == 990 ) return 990;
- if(i == 991 ) return 991;
- if(i == 992 ) return 992;
- if(i == 993 ) return 993;
- if(i == 994 ) return 994;
- if(i == 995 ) return 995;
- if(i == 996 ) return 996;
- if(i == 997 ) return 997;
- if(i == 998 ) return 998;
- if(i == 999 ) return 999;
- if(i == 1000 ) return 1000;
- if(i == 1001 ) return 1001;
- if(i == 1002 ) return 1002;
- if(i == 1003 ) return 1003;
- if(i == 1004 ) return 1004;
- if(i == 1005 ) return 1005;
- if(i == 1006 ) return 1006;
- if(i == 1007 ) return 1007;
- if(i == 1008 ) return 1008;
- if(i == 1009 ) return 1009;
- if(i == 1010 ) return 1010;
- if(i == 1011 ) return 1011;
- if(i == 1012 ) return 1012;
- if(i == 1013 ) return 1013;
- if(i == 1014 ) return 1014;
- if(i == 1015 ) return 1015;
- if(i == 1016 ) return 1016;
- if(i == 1017 ) return 1017;
- if(i == 1018 ) return 1018;
- if(i == 1019 ) return 1019;
- if(i == 1020 ) return 1020;
- if(i == 1021 ) return 1021;
- if(i == 1022 ) return 1022;
- if(i == 1023 ) return 1023;
- if(i == 1024 ) return 1024;
- if(i == 1025 ) return 1025;
- if(i == 1026 ) return 1026;
- if(i == 1027 ) return 1027;
- if(i == 1028 ) return 1028;
- if(i == 1029 ) return 1029;
- if(i == 1030 ) return 1030;
- if(i == 1031 ) return 1031;
- if(i == 1032 ) return 1032;
- if(i == 1033 ) return 1033;
- if(i == 1034 ) return 1034;
- if(i == 1035 ) return 1035;
- if(i == 1036 ) return 1036;
- if(i == 1037 ) return 1037;
- if(i == 1038 ) return 1038;
- if(i == 1039 ) return 1039;
- if(i == 1040 ) return 1040;
- if(i == 1041 ) return 1041;
- if(i == 1042 ) return 1042;
- if(i == 1043 ) return 1043;
- if(i == 1044 ) return 1044;
- if(i == 1045 ) return 1045;
- if(i == 1046 ) return 1046;
- if(i == 1047 ) return 1047;
- if(i == 1048 ) return 1048;
- if(i == 1049 ) return 1049;
- if(i == 1050 ) return 1050;
- if(i == 1051 ) return 1051;
- if(i == 1052 ) return 1052;
- if(i == 1053 ) return 1053;
- if(i == 1054 ) return 1054;
- if(i == 1055 ) return 1055;
- if(i == 1056 ) return 1056;
- if(i == 1057 ) return 1057;
- if(i == 1058 ) return 1058;
- if(i == 1059 ) return 1059;
- if(i == 1060 ) return 1060;
- if(i == 1061 ) return 1061;
- if(i == 1062 ) return 1062;
- if(i == 1063 ) return 1063;
- if(i == 1064 ) return 1064;
- if(i == 1065 ) return 1065;
- if(i == 1066 ) return 1066;
- if(i == 1067 ) return 1067;
- if(i == 1068 ) return 1068;
- if(i == 1069 ) return 1069;
- if(i == 1070 ) return 1070;
- if(i == 1071 ) return 1071;
- if(i == 1072 ) return 1072;
- if(i == 1073 ) return 1073;
- if(i == 1074 ) return 1074;
- if(i == 1075 ) return 1075;
- if(i == 1076 ) return 1076;
- if(i == 1077 ) return 1077;
- if(i == 1078 ) return 1078;
- if(i == 1079 ) return 1079;
- if(i == 1080 ) return 1080;
- if(i == 1081 ) return 1081;
- if(i == 1082 ) return 1082;
- if(i == 1083 ) return 1083;
- if(i == 1084 ) return 1084;
- if(i == 1085 ) return 1085;
- if(i == 1086 ) return 1086;
- if(i == 1087 ) return 1087;
- if(i == 1088 ) return 1088;
- if(i == 1089 ) return 1089;
- if(i == 1090 ) return 1090;
- if(i == 1091 ) return 1091;
- if(i == 1092 ) return 1092;
- if(i == 1093 ) return 1093;
- if(i == 1094 ) return 1094;
- if(i == 1095 ) return 1095;
- if(i == 1096 ) return 1096;
- if(i == 1097 ) return 1097;
- if(i == 1098 ) return 1098;
- if(i == 1099 ) return 1099;
- if(i == 1100 ) return 1100;
- if(i == 1101 ) return 1101;
- if(i == 1102 ) return 1102;
- if(i == 1103 ) return 1103;
- if(i == 1104 ) return 1104;
- if(i == 1105 ) return 1105;
- if(i == 1106 ) return 1106;
- if(i == 1107 ) return 1107;
- if(i == 1108 ) return 1108;
- if(i == 1109 ) return 1109;
- if(i == 1110 ) return 1110;
- if(i == 1111 ) return 1111;
- if(i == 1112 ) return 1112;
- if(i == 1113 ) return 1113;
- if(i == 1114 ) return 1114;
- if(i == 1115 ) return 1115;
- if(i == 1116 ) return 1116;
- if(i == 1117 ) return 1117;
- if(i == 1118 ) return 1118;
- if(i == 1119 ) return 1119;
- if(i == 1120 ) return 1120;
- if(i == 1121 ) return 1121;
- if(i == 1122 ) return 1122;
- if(i == 1123 ) return 1123;
- if(i == 1124 ) return 1124;
- if(i == 1125 ) return 1125;
- if(i == 1126 ) return 1126;
- if(i == 1127 ) return 1127;
- if(i == 1128 ) return 1128;
- if(i == 1129 ) return 1129;
- if(i == 1130 ) return 1130;
- if(i == 1131 ) return 1131;
- if(i == 1132 ) return 1132;
- if(i == 1133 ) return 1133;
- if(i == 1134 ) return 1134;
- if(i == 1135 ) return 1135;
- if(i == 1136 ) return 1136;
- if(i == 1137 ) return 1137;
- if(i == 1138 ) return 1138;
- if(i == 1139 ) return 1139;
- if(i == 1140 ) return 1140;
- if(i == 1141 ) return 1141;
- if(i == 1142 ) return 1142;
- if(i == 1143 ) return 1143;
- if(i == 1144 ) return 1144;
- if(i == 1145 ) return 1145;
- if(i == 1146 ) return 1146;
- if(i == 1147 ) return 1147;
- if(i == 1148 ) return 1148;
- if(i == 1149 ) return 1149;
- if(i == 1150 ) return 1150;
- if(i == 1151 ) return 1151;
- if(i == 1152 ) return 1152;
- if(i == 1153 ) return 1153;
- if(i == 1154 ) return 1154;
- if(i == 1155 ) return 1155;
- if(i == 1156 ) return 1156;
- if(i == 1157 ) return 1157;
- if(i == 1158 ) return 1158;
- if(i == 1159 ) return 1159;
- if(i == 1160 ) return 1160;
- if(i == 1161 ) return 1161;
- if(i == 1162 ) return 1162;
- if(i == 1163 ) return 1163;
- if(i == 1164 ) return 1164;
- if(i == 1165 ) return 1165;
- if(i == 1166 ) return 1166;
- if(i == 1167 ) return 1167;
- if(i == 1168 ) return 1168;
- if(i == 1169 ) return 1169;
- if(i == 1170 ) return 1170;
- if(i == 1171 ) return 1171;
- if(i == 1172 ) return 1172;
- if(i == 1173 ) return 1173;
- if(i == 1174 ) return 1174;
- if(i == 1175 ) return 1175;
- if(i == 1176 ) return 1176;
- if(i == 1177 ) return 1177;
- if(i == 1178 ) return 1178;
- if(i == 1179 ) return 1179;
- if(i == 1180 ) return 1180;
- if(i == 1181 ) return 1181;
- if(i == 1182 ) return 1182;
- if(i == 1183 ) return 1183;
- if(i == 1184 ) return 1184;
- if(i == 1185 ) return 1185;
- if(i == 1186 ) return 1186;
- if(i == 1187 ) return 1187;
- if(i == 1188 ) return 1188;
- if(i == 1189 ) return 1189;
- if(i == 1190 ) return 1190;
- if(i == 1191 ) return 1191;
- if(i == 1192 ) return 1192;
- if(i == 1193 ) return 1193;
- if(i == 1194 ) return 1194;
- if(i == 1195 ) return 1195;
- if(i == 1196 ) return 1196;
- if(i == 1197 ) return 1197;
- if(i == 1198 ) return 1198;
- if(i == 1199 ) return 1199;
- if(i == 1200 ) return 1200;
- if(i == 1201 ) return 1201;
- if(i == 1202 ) return 1202;
- if(i == 1203 ) return 1203;
- if(i == 1204 ) return 1204;
- if(i == 1205 ) return 1205;
- if(i == 1206 ) return 1206;
- if(i == 1207 ) return 1207;
- if(i == 1208 ) return 1208;
- if(i == 1209 ) return 1209;
- if(i == 1210 ) return 1210;
- if(i == 1211 ) return 1211;
- if(i == 1212 ) return 1212;
- if(i == 1213 ) return 1213;
- if(i == 1214 ) return 1214;
- if(i == 1215 ) return 1215;
- if(i == 1216 ) return 1216;
- if(i == 1217 ) return 1217;
- if(i == 1218 ) return 1218;
- if(i == 1219 ) return 1219;
- if(i == 1220 ) return 1220;
- if(i == 1221 ) return 1221;
- if(i == 1222 ) return 1222;
- if(i == 1223 ) return 1223;
- if(i == 1224 ) return 1224;
- if(i == 1225 ) return 1225;
- if(i == 1226 ) return 1226;
- if(i == 1227 ) return 1227;
- if(i == 1228 ) return 1228;
- if(i == 1229 ) return 1229;
- if(i == 1230 ) return 1230;
- if(i == 1231 ) return 1231;
- if(i == 1232 ) return 1232;
- if(i == 1233 ) return 1233;
- if(i == 1234 ) return 1234;
- if(i == 1235 ) return 1235;
- if(i == 1236 ) return 1236;
- if(i == 1237 ) return 1237;
- if(i == 1238 ) return 1238;
- if(i == 1239 ) return 1239;
- if(i == 1240 ) return 1240;
- if(i == 1241 ) return 1241;
- if(i == 1242 ) return 1242;
- if(i == 1243 ) return 1243;
- if(i == 1244 ) return 1244;
- if(i == 1245 ) return 1245;
- if(i == 1246 ) return 1246;
- if(i == 1247 ) return 1247;
- if(i == 1248 ) return 1248;
- if(i == 1249 ) return 1249;
- if(i == 1250 ) return 1250;
- if(i == 1251 ) return 1251;
- if(i == 1252 ) return 1252;
- if(i == 1253 ) return 1253;
- if(i == 1254 ) return 1254;
- if(i == 1255 ) return 1255;
- if(i == 1256 ) return 1256;
- if(i == 1257 ) return 1257;
- if(i == 1258 ) return 1258;
- if(i == 1259 ) return 1259;
- if(i == 1260 ) return 1260;
- if(i == 1261 ) return 1261;
- if(i == 1262 ) return 1262;
- if(i == 1263 ) return 1263;
- if(i == 1264 ) return 1264;
- if(i == 1265 ) return 1265;
- if(i == 1266 ) return 1266;
- if(i == 1267 ) return 1267;
- if(i == 1268 ) return 1268;
- if(i == 1269 ) return 1269;
- if(i == 1270 ) return 1270;
- if(i == 1271 ) return 1271;
- if(i == 1272 ) return 1272;
- if(i == 1273 ) return 1273;
- if(i == 1274 ) return 1274;
- if(i == 1275 ) return 1275;
- if(i == 1276 ) return 1276;
- if(i == 1277 ) return 1277;
- if(i == 1278 ) return 1278;
- if(i == 1279 ) return 1279;
- if(i == 1280 ) return 1280;
- if(i == 1281 ) return 1281;
- if(i == 1282 ) return 1282;
- if(i == 1283 ) return 1283;
- if(i == 1284 ) return 1284;
- if(i == 1285 ) return 1285;
- if(i == 1286 ) return 1286;
- if(i == 1287 ) return 1287;
- if(i == 1288 ) return 1288;
- if(i == 1289 ) return 1289;
- if(i == 1290 ) return 1290;
- if(i == 1291 ) return 1291;
- if(i == 1292 ) return 1292;
- if(i == 1293 ) return 1293;
- if(i == 1294 ) return 1294;
- if(i == 1295 ) return 1295;
- if(i == 1296 ) return 1296;
- if(i == 1297 ) return 1297;
- if(i == 1298 ) return 1298;
- if(i == 1299 ) return 1299;
- if(i == 1300 ) return 1300;
- if(i == 1301 ) return 1301;
- if(i == 1302 ) return 1302;
- if(i == 1303 ) return 1303;
- if(i == 1304 ) return 1304;
- if(i == 1305 ) return 1305;
- if(i == 1306 ) return 1306;
- if(i == 1307 ) return 1307;
- if(i == 1308 ) return 1308;
- if(i == 1309 ) return 1309;
- if(i == 1310 ) return 1310;
- if(i == 1311 ) return 1311;
- if(i == 1312 ) return 1312;
- if(i == 1313 ) return 1313;
- if(i == 1314 ) return 1314;
- if(i == 1315 ) return 1315;
- if(i == 1316 ) return 1316;
- if(i == 1317 ) return 1317;
- if(i == 1318 ) return 1318;
- if(i == 1319 ) return 1319;
- if(i == 1320 ) return 1320;
- if(i == 1321 ) return 1321;
- if(i == 1322 ) return 1322;
- if(i == 1323 ) return 1323;
- if(i == 1324 ) return 1324;
- if(i == 1325 ) return 1325;
- if(i == 1326 ) return 1326;
- if(i == 1327 ) return 1327;
- if(i == 1328 ) return 1328;
- if(i == 1329 ) return 1329;
- if(i == 1330 ) return 1330;
- if(i == 1331 ) return 1331;
- if(i == 1332 ) return 1332;
- if(i == 1333 ) return 1333;
- if(i == 1334 ) return 1334;
- if(i == 1335 ) return 1335;
- if(i == 1336 ) return 1336;
- if(i == 1337 ) return 1337;
- if(i == 1338 ) return 1338;
- if(i == 1339 ) return 1339;
- if(i == 1340 ) return 1340;
- if(i == 1341 ) return 1341;
- if(i == 1342 ) return 1342;
- if(i == 1343 ) return 1343;
- if(i == 1344 ) return 1344;
- if(i == 1345 ) return 1345;
- if(i == 1346 ) return 1346;
- if(i == 1347 ) return 1347;
- if(i == 1348 ) return 1348;
- if(i == 1349 ) return 1349;
- if(i == 1350 ) return 1350;
- if(i == 1351 ) return 1351;
- if(i == 1352 ) return 1352;
- if(i == 1353 ) return 1353;
- if(i == 1354 ) return 1354;
- if(i == 1355 ) return 1355;
- if(i == 1356 ) return 1356;
- if(i == 1357 ) return 1357;
- if(i == 1358 ) return 1358;
- if(i == 1359 ) return 1359;
- if(i == 1360 ) return 1360;
- if(i == 1361 ) return 1361;
- if(i == 1362 ) return 1362;
- if(i == 1363 ) return 1363;
- if(i == 1364 ) return 1364;
- if(i == 1365 ) return 1365;
- if(i == 1366 ) return 1366;
- if(i == 1367 ) return 1367;
- if(i == 1368 ) return 1368;
- if(i == 1369 ) return 1369;
- if(i == 1370 ) return 1370;
- if(i == 1371 ) return 1371;
- if(i == 1372 ) return 1372;
- if(i == 1373 ) return 1373;
- if(i == 1374 ) return 1374;
- if(i == 1375 ) return 1375;
- if(i == 1376 ) return 1376;
- if(i == 1377 ) return 1377;
- if(i == 1378 ) return 1378;
- if(i == 1379 ) return 1379;
- if(i == 1380 ) return 1380;
- if(i == 1381 ) return 1381;
- if(i == 1382 ) return 1382;
- if(i == 1383 ) return 1383;
- if(i == 1384 ) return 1384;
- if(i == 1385 ) return 1385;
- if(i == 1386 ) return 1386;
- if(i == 1387 ) return 1387;
- if(i == 1388 ) return 1388;
- if(i == 1389 ) return 1389;
- if(i == 1390 ) return 1390;
- if(i == 1391 ) return 1391;
- if(i == 1392 ) return 1392;
- if(i == 1393 ) return 1393;
- if(i == 1394 ) return 1394;
- if(i == 1395 ) return 1395;
- if(i == 1396 ) return 1396;
- if(i == 1397 ) return 1397;
- if(i == 1398 ) return 1398;
- if(i == 1399 ) return 1399;
- if(i == 1400 ) return 1400;
- if(i == 1401 ) return 1401;
- if(i == 1402 ) return 1402;
- if(i == 1403 ) return 1403;
- if(i == 1404 ) return 1404;
- if(i == 1405 ) return 1405;
- if(i == 1406 ) return 1406;
- if(i == 1407 ) return 1407;
- if(i == 1408 ) return 1408;
- if(i == 1409 ) return 1409;
- if(i == 1410 ) return 1410;
- if(i == 1411 ) return 1411;
- if(i == 1412 ) return 1412;
- if(i == 1413 ) return 1413;
- if(i == 1414 ) return 1414;
- if(i == 1415 ) return 1415;
- if(i == 1416 ) return 1416;
- if(i == 1417 ) return 1417;
- if(i == 1418 ) return 1418;
- if(i == 1419 ) return 1419;
- if(i == 1420 ) return 1420;
- if(i == 1421 ) return 1421;
- if(i == 1422 ) return 1422;
- if(i == 1423 ) return 1423;
- if(i == 1424 ) return 1424;
- if(i == 1425 ) return 1425;
- if(i == 1426 ) return 1426;
- if(i == 1427 ) return 1427;
- if(i == 1428 ) return 1428;
- if(i == 1429 ) return 1429;
- if(i == 1430 ) return 1430;
- if(i == 1431 ) return 1431;
- if(i == 1432 ) return 1432;
- if(i == 1433 ) return 1433;
- if(i == 1434 ) return 1434;
- if(i == 1435 ) return 1435;
- if(i == 1436 ) return 1436;
- if(i == 1437 ) return 1437;
- if(i == 1438 ) return 1438;
- if(i == 1439 ) return 1439;
- if(i == 1440 ) return 1440;
- if(i == 1441 ) return 1441;
- if(i == 1442 ) return 1442;
- if(i == 1443 ) return 1443;
- if(i == 1444 ) return 1444;
- if(i == 1445 ) return 1445;
- if(i == 1446 ) return 1446;
- if(i == 1447 ) return 1447;
- if(i == 1448 ) return 1448;
- if(i == 1449 ) return 1449;
- if(i == 1450 ) return 1450;
- if(i == 1451 ) return 1451;
- if(i == 1452 ) return 1452;
- if(i == 1453 ) return 1453;
- if(i == 1454 ) return 1454;
- if(i == 1455 ) return 1455;
- if(i == 1456 ) return 1456;
- if(i == 1457 ) return 1457;
- if(i == 1458 ) return 1458;
- if(i == 1459 ) return 1459;
- if(i == 1460 ) return 1460;
- if(i == 1461 ) return 1461;
- if(i == 1462 ) return 1462;
- if(i == 1463 ) return 1463;
- if(i == 1464 ) return 1464;
- if(i == 1465 ) return 1465;
- if(i == 1466 ) return 1466;
- if(i == 1467 ) return 1467;
- if(i == 1468 ) return 1468;
- if(i == 1469 ) return 1469;
- if(i == 1470 ) return 1470;
- if(i == 1471 ) return 1471;
- if(i == 1472 ) return 1472;
- if(i == 1473 ) return 1473;
- if(i == 1474 ) return 1474;
- if(i == 1475 ) return 1475;
- if(i == 1476 ) return 1476;
- if(i == 1477 ) return 1477;
- if(i == 1478 ) return 1478;
- if(i == 1479 ) return 1479;
- if(i == 1480 ) return 1480;
- if(i == 1481 ) return 1481;
- if(i == 1482 ) return 1482;
- if(i == 1483 ) return 1483;
- if(i == 1484 ) return 1484;
- if(i == 1485 ) return 1485;
- if(i == 1486 ) return 1486;
- if(i == 1487 ) return 1487;
- if(i == 1488 ) return 1488;
- if(i == 1489 ) return 1489;
- if(i == 1490 ) return 1490;
- if(i == 1491 ) return 1491;
- if(i == 1492 ) return 1492;
- if(i == 1493 ) return 1493;
- if(i == 1494 ) return 1494;
- if(i == 1495 ) return 1495;
- if(i == 1496 ) return 1496;
- if(i == 1497 ) return 1497;
- if(i == 1498 ) return 1498;
- if(i == 1499 ) return 1499;
- if(i == 1500 ) return 1500;
- if(i == 1501 ) return 1501;
- if(i == 1502 ) return 1502;
- if(i == 1503 ) return 1503;
- if(i == 1504 ) return 1504;
- if(i == 1505 ) return 1505;
- if(i == 1506 ) return 1506;
- if(i == 1507 ) return 1507;
- if(i == 1508 ) return 1508;
- if(i == 1509 ) return 1509;
- if(i == 1510 ) return 1510;
- if(i == 1511 ) return 1511;
- if(i == 1512 ) return 1512;
- if(i == 1513 ) return 1513;
- if(i == 1514 ) return 1514;
- if(i == 1515 ) return 1515;
- if(i == 1516 ) return 1516;
- if(i == 1517 ) return 1517;
- if(i == 1518 ) return 1518;
- if(i == 1519 ) return 1519;
- if(i == 1520 ) return 1520;
- if(i == 1521 ) return 1521;
- if(i == 1522 ) return 1522;
- if(i == 1523 ) return 1523;
- if(i == 1524 ) return 1524;
- if(i == 1525 ) return 1525;
- if(i == 1526 ) return 1526;
- if(i == 1527 ) return 1527;
- if(i == 1528 ) return 1528;
- if(i == 1529 ) return 1529;
- if(i == 1530 ) return 1530;
- if(i == 1531 ) return 1531;
- if(i == 1532 ) return 1532;
- if(i == 1533 ) return 1533;
- if(i == 1534 ) return 1534;
- if(i == 1535 ) return 1535;
- if(i == 1536 ) return 1536;
- if(i == 1537 ) return 1537;
- if(i == 1538 ) return 1538;
- if(i == 1539 ) return 1539;
- if(i == 1540 ) return 1540;
- if(i == 1541 ) return 1541;
- if(i == 1542 ) return 1542;
- if(i == 1543 ) return 1543;
- if(i == 1544 ) return 1544;
- if(i == 1545 ) return 1545;
- if(i == 1546 ) return 1546;
- if(i == 1547 ) return 1547;
- if(i == 1548 ) return 1548;
- if(i == 1549 ) return 1549;
- if(i == 1550 ) return 1550;
- if(i == 1551 ) return 1551;
- if(i == 1552 ) return 1552;
- if(i == 1553 ) return 1553;
- if(i == 1554 ) return 1554;
- if(i == 1555 ) return 1555;
- if(i == 1556 ) return 1556;
- if(i == 1557 ) return 1557;
- if(i == 1558 ) return 1558;
- if(i == 1559 ) return 1559;
- if(i == 1560 ) return 1560;
- if(i == 1561 ) return 1561;
- if(i == 1562 ) return 1562;
- if(i == 1563 ) return 1563;
- if(i == 1564 ) return 1564;
- if(i == 1565 ) return 1565;
- if(i == 1566 ) return 1566;
- if(i == 1567 ) return 1567;
- if(i == 1568 ) return 1568;
- if(i == 1569 ) return 1569;
- if(i == 1570 ) return 1570;
- if(i == 1571 ) return 1571;
- if(i == 1572 ) return 1572;
- if(i == 1573 ) return 1573;
- if(i == 1574 ) return 1574;
- if(i == 1575 ) return 1575;
- if(i == 1576 ) return 1576;
- if(i == 1577 ) return 1577;
- if(i == 1578 ) return 1578;
- if(i == 1579 ) return 1579;
- if(i == 1580 ) return 1580;
- if(i == 1581 ) return 1581;
- if(i == 1582 ) return 1582;
- if(i == 1583 ) return 1583;
- if(i == 1584 ) return 1584;
- if(i == 1585 ) return 1585;
- if(i == 1586 ) return 1586;
- if(i == 1587 ) return 1587;
- if(i == 1588 ) return 1588;
- if(i == 1589 ) return 1589;
- if(i == 1590 ) return 1590;
- if(i == 1591 ) return 1591;
- if(i == 1592 ) return 1592;
- if(i == 1593 ) return 1593;
- if(i == 1594 ) return 1594;
- if(i == 1595 ) return 1595;
- if(i == 1596 ) return 1596;
- if(i == 1597 ) return 1597;
- if(i == 1598 ) return 1598;
- if(i == 1599 ) return 1599;
- if(i == 1600 ) return 1600;
- if(i == 1601 ) return 1601;
- if(i == 1602 ) return 1602;
- if(i == 1603 ) return 1603;
- if(i == 1604 ) return 1604;
- if(i == 1605 ) return 1605;
- if(i == 1606 ) return 1606;
- if(i == 1607 ) return 1607;
- if(i == 1608 ) return 1608;
- if(i == 1609 ) return 1609;
- if(i == 1610 ) return 1610;
- if(i == 1611 ) return 1611;
- if(i == 1612 ) return 1612;
- if(i == 1613 ) return 1613;
- if(i == 1614 ) return 1614;
- if(i == 1615 ) return 1615;
- if(i == 1616 ) return 1616;
- if(i == 1617 ) return 1617;
- if(i == 1618 ) return 1618;
- if(i == 1619 ) return 1619;
- if(i == 1620 ) return 1620;
- if(i == 1621 ) return 1621;
- if(i == 1622 ) return 1622;
- if(i == 1623 ) return 1623;
- if(i == 1624 ) return 1624;
- if(i == 1625 ) return 1625;
- if(i == 1626 ) return 1626;
- if(i == 1627 ) return 1627;
- if(i == 1628 ) return 1628;
- if(i == 1629 ) return 1629;
- if(i == 1630 ) return 1630;
- if(i == 1631 ) return 1631;
- if(i == 1632 ) return 1632;
- if(i == 1633 ) return 1633;
- if(i == 1634 ) return 1634;
- if(i == 1635 ) return 1635;
- if(i == 1636 ) return 1636;
- if(i == 1637 ) return 1637;
- if(i == 1638 ) return 1638;
- if(i == 1639 ) return 1639;
- if(i == 1640 ) return 1640;
- if(i == 1641 ) return 1641;
- if(i == 1642 ) return 1642;
- if(i == 1643 ) return 1643;
- if(i == 1644 ) return 1644;
- if(i == 1645 ) return 1645;
- if(i == 1646 ) return 1646;
- if(i == 1647 ) return 1647;
- if(i == 1648 ) return 1648;
- if(i == 1649 ) return 1649;
- if(i == 1650 ) return 1650;
- if(i == 1651 ) return 1651;
- if(i == 1652 ) return 1652;
- if(i == 1653 ) return 1653;
- if(i == 1654 ) return 1654;
- if(i == 1655 ) return 1655;
- if(i == 1656 ) return 1656;
- if(i == 1657 ) return 1657;
- if(i == 1658 ) return 1658;
- if(i == 1659 ) return 1659;
- if(i == 1660 ) return 1660;
- if(i == 1661 ) return 1661;
- if(i == 1662 ) return 1662;
- if(i == 1663 ) return 1663;
- if(i == 1664 ) return 1664;
- if(i == 1665 ) return 1665;
- if(i == 1666 ) return 1666;
- if(i == 1667 ) return 1667;
- if(i == 1668 ) return 1668;
- if(i == 1669 ) return 1669;
- if(i == 1670 ) return 1670;
- if(i == 1671 ) return 1671;
- if(i == 1672 ) return 1672;
- if(i == 1673 ) return 1673;
- if(i == 1674 ) return 1674;
- if(i == 1675 ) return 1675;
- if(i == 1676 ) return 1676;
- if(i == 1677 ) return 1677;
- if(i == 1678 ) return 1678;
- if(i == 1679 ) return 1679;
- if(i == 1680 ) return 1680;
- if(i == 1681 ) return 1681;
- if(i == 1682 ) return 1682;
- if(i == 1683 ) return 1683;
- if(i == 1684 ) return 1684;
- if(i == 1685 ) return 1685;
- if(i == 1686 ) return 1686;
- if(i == 1687 ) return 1687;
- if(i == 1688 ) return 1688;
- if(i == 1689 ) return 1689;
- if(i == 1690 ) return 1690;
- if(i == 1691 ) return 1691;
- if(i == 1692 ) return 1692;
- if(i == 1693 ) return 1693;
- if(i == 1694 ) return 1694;
- if(i == 1695 ) return 1695;
- if(i == 1696 ) return 1696;
- if(i == 1697 ) return 1697;
- if(i == 1698 ) return 1698;
- if(i == 1699 ) return 1699;
- if(i == 1700 ) return 1700;
- if(i == 1701 ) return 1701;
- if(i == 1702 ) return 1702;
- if(i == 1703 ) return 1703;
- if(i == 1704 ) return 1704;
- if(i == 1705 ) return 1705;
- if(i == 1706 ) return 1706;
- if(i == 1707 ) return 1707;
- if(i == 1708 ) return 1708;
- if(i == 1709 ) return 1709;
- if(i == 1710 ) return 1710;
- if(i == 1711 ) return 1711;
- if(i == 1712 ) return 1712;
- if(i == 1713 ) return 1713;
- if(i == 1714 ) return 1714;
- if(i == 1715 ) return 1715;
- if(i == 1716 ) return 1716;
- if(i == 1717 ) return 1717;
- if(i == 1718 ) return 1718;
- if(i == 1719 ) return 1719;
- if(i == 1720 ) return 1720;
- if(i == 1721 ) return 1721;
- if(i == 1722 ) return 1722;
- if(i == 1723 ) return 1723;
- if(i == 1724 ) return 1724;
- if(i == 1725 ) return 1725;
- if(i == 1726 ) return 1726;
- if(i == 1727 ) return 1727;
- if(i == 1728 ) return 1728;
- if(i == 1729 ) return 1729;
- if(i == 1730 ) return 1730;
- if(i == 1731 ) return 1731;
- if(i == 1732 ) return 1732;
- if(i == 1733 ) return 1733;
- if(i == 1734 ) return 1734;
- if(i == 1735 ) return 1735;
- if(i == 1736 ) return 1736;
- if(i == 1737 ) return 1737;
- if(i == 1738 ) return 1738;
- if(i == 1739 ) return 1739;
- if(i == 1740 ) return 1740;
- if(i == 1741 ) return 1741;
- if(i == 1742 ) return 1742;
- if(i == 1743 ) return 1743;
- if(i == 1744 ) return 1744;
- if(i == 1745 ) return 1745;
- if(i == 1746 ) return 1746;
- if(i == 1747 ) return 1747;
- if(i == 1748 ) return 1748;
- if(i == 1749 ) return 1749;
- if(i == 1750 ) return 1750;
- if(i == 1751 ) return 1751;
- if(i == 1752 ) return 1752;
- if(i == 1753 ) return 1753;
- if(i == 1754 ) return 1754;
- if(i == 1755 ) return 1755;
- if(i == 1756 ) return 1756;
- if(i == 1757 ) return 1757;
- if(i == 1758 ) return 1758;
- if(i == 1759 ) return 1759;
- if(i == 1760 ) return 1760;
- if(i == 1761 ) return 1761;
- if(i == 1762 ) return 1762;
- if(i == 1763 ) return 1763;
- if(i == 1764 ) return 1764;
- if(i == 1765 ) return 1765;
- if(i == 1766 ) return 1766;
- if(i == 1767 ) return 1767;
- if(i == 1768 ) return 1768;
- if(i == 1769 ) return 1769;
- if(i == 1770 ) return 1770;
- if(i == 1771 ) return 1771;
- if(i == 1772 ) return 1772;
- if(i == 1773 ) return 1773;
- if(i == 1774 ) return 1774;
- if(i == 1775 ) return 1775;
- if(i == 1776 ) return 1776;
- if(i == 1777 ) return 1777;
- if(i == 1778 ) return 1778;
- if(i == 1779 ) return 1779;
- if(i == 1780 ) return 1780;
- if(i == 1781 ) return 1781;
- if(i == 1782 ) return 1782;
- if(i == 1783 ) return 1783;
- if(i == 1784 ) return 1784;
- if(i == 1785 ) return 1785;
- if(i == 1786 ) return 1786;
- if(i == 1787 ) return 1787;
- if(i == 1788 ) return 1788;
- if(i == 1789 ) return 1789;
- if(i == 1790 ) return 1790;
- if(i == 1791 ) return 1791;
- if(i == 1792 ) return 1792;
- if(i == 1793 ) return 1793;
- if(i == 1794 ) return 1794;
- if(i == 1795 ) return 1795;
- if(i == 1796 ) return 1796;
- if(i == 1797 ) return 1797;
- if(i == 1798 ) return 1798;
- if(i == 1799 ) return 1799;
- if(i == 1800 ) return 1800;
- if(i == 1801 ) return 1801;
- if(i == 1802 ) return 1802;
- if(i == 1803 ) return 1803;
- if(i == 1804 ) return 1804;
- if(i == 1805 ) return 1805;
- if(i == 1806 ) return 1806;
- if(i == 1807 ) return 1807;
- if(i == 1808 ) return 1808;
- if(i == 1809 ) return 1809;
- if(i == 1810 ) return 1810;
- if(i == 1811 ) return 1811;
- if(i == 1812 ) return 1812;
- if(i == 1813 ) return 1813;
- if(i == 1814 ) return 1814;
- if(i == 1815 ) return 1815;
- if(i == 1816 ) return 1816;
- if(i == 1817 ) return 1817;
- if(i == 1818 ) return 1818;
- if(i == 1819 ) return 1819;
- if(i == 1820 ) return 1820;
- if(i == 1821 ) return 1821;
- if(i == 1822 ) return 1822;
- if(i == 1823 ) return 1823;
- if(i == 1824 ) return 1824;
- if(i == 1825 ) return 1825;
- if(i == 1826 ) return 1826;
- if(i == 1827 ) return 1827;
- if(i == 1828 ) return 1828;
- if(i == 1829 ) return 1829;
- if(i == 1830 ) return 1830;
- if(i == 1831 ) return 1831;
- if(i == 1832 ) return 1832;
- if(i == 1833 ) return 1833;
- if(i == 1834 ) return 1834;
- if(i == 1835 ) return 1835;
- if(i == 1836 ) return 1836;
- if(i == 1837 ) return 1837;
- if(i == 1838 ) return 1838;
- if(i == 1839 ) return 1839;
- if(i == 1840 ) return 1840;
- if(i == 1841 ) return 1841;
- if(i == 1842 ) return 1842;
- if(i == 1843 ) return 1843;
- if(i == 1844 ) return 1844;
- if(i == 1845 ) return 1845;
- if(i == 1846 ) return 1846;
- if(i == 1847 ) return 1847;
- if(i == 1848 ) return 1848;
- if(i == 1849 ) return 1849;
- if(i == 1850 ) return 1850;
- if(i == 1851 ) return 1851;
- if(i == 1852 ) return 1852;
- if(i == 1853 ) return 1853;
- if(i == 1854 ) return 1854;
- if(i == 1855 ) return 1855;
- if(i == 1856 ) return 1856;
- if(i == 1857 ) return 1857;
- if(i == 1858 ) return 1858;
- if(i == 1859 ) return 1859;
- if(i == 1860 ) return 1860;
- if(i == 1861 ) return 1861;
- if(i == 1862 ) return 1862;
- if(i == 1863 ) return 1863;
- if(i == 1864 ) return 1864;
- if(i == 1865 ) return 1865;
- if(i == 1866 ) return 1866;
- if(i == 1867 ) return 1867;
- if(i == 1868 ) return 1868;
- if(i == 1869 ) return 1869;
- if(i == 1870 ) return 1870;
- if(i == 1871 ) return 1871;
- if(i == 1872 ) return 1872;
- if(i == 1873 ) return 1873;
- if(i == 1874 ) return 1874;
- if(i == 1875 ) return 1875;
- if(i == 1876 ) return 1876;
- if(i == 1877 ) return 1877;
- if(i == 1878 ) return 1878;
- if(i == 1879 ) return 1879;
- if(i == 1880 ) return 1880;
- if(i == 1881 ) return 1881;
- if(i == 1882 ) return 1882;
- if(i == 1883 ) return 1883;
- if(i == 1884 ) return 1884;
- if(i == 1885 ) return 1885;
- if(i == 1886 ) return 1886;
- if(i == 1887 ) return 1887;
- if(i == 1888 ) return 1888;
- if(i == 1889 ) return 1889;
- if(i == 1890 ) return 1890;
- if(i == 1891 ) return 1891;
- if(i == 1892 ) return 1892;
- if(i == 1893 ) return 1893;
- if(i == 1894 ) return 1894;
- if(i == 1895 ) return 1895;
- if(i == 1896 ) return 1896;
- if(i == 1897 ) return 1897;
- if(i == 1898 ) return 1898;
- if(i == 1899 ) return 1899;
- if(i == 1900 ) return 1900;
- if(i == 1901 ) return 1901;
- if(i == 1902 ) return 1902;
- if(i == 1903 ) return 1903;
- if(i == 1904 ) return 1904;
- if(i == 1905 ) return 1905;
- if(i == 1906 ) return 1906;
- if(i == 1907 ) return 1907;
- if(i == 1908 ) return 1908;
- if(i == 1909 ) return 1909;
- if(i == 1910 ) return 1910;
- if(i == 1911 ) return 1911;
- if(i == 1912 ) return 1912;
- if(i == 1913 ) return 1913;
- if(i == 1914 ) return 1914;
- if(i == 1915 ) return 1915;
- if(i == 1916 ) return 1916;
- if(i == 1917 ) return 1917;
- if(i == 1918 ) return 1918;
- if(i == 1919 ) return 1919;
- if(i == 1920 ) return 1920;
- if(i == 1921 ) return 1921;
- if(i == 1922 ) return 1922;
- if(i == 1923 ) return 1923;
- if(i == 1924 ) return 1924;
- if(i == 1925 ) return 1925;
- if(i == 1926 ) return 1926;
- if(i == 1927 ) return 1927;
- if(i == 1928 ) return 1928;
- if(i == 1929 ) return 1929;
- if(i == 1930 ) return 1930;
- if(i == 1931 ) return 1931;
- if(i == 1932 ) return 1932;
- if(i == 1933 ) return 1933;
- if(i == 1934 ) return 1934;
- if(i == 1935 ) return 1935;
- if(i == 1936 ) return 1936;
- if(i == 1937 ) return 1937;
- if(i == 1938 ) return 1938;
- if(i == 1939 ) return 1939;
- if(i == 1940 ) return 1940;
- if(i == 1941 ) return 1941;
- if(i == 1942 ) return 1942;
- if(i == 1943 ) return 1943;
- if(i == 1944 ) return 1944;
- if(i == 1945 ) return 1945;
- if(i == 1946 ) return 1946;
- if(i == 1947 ) return 1947;
- if(i == 1948 ) return 1948;
- if(i == 1949 ) return 1949;
- if(i == 1950 ) return 1950;
- if(i == 1951 ) return 1951;
- if(i == 1952 ) return 1952;
- if(i == 1953 ) return 1953;
- if(i == 1954 ) return 1954;
- if(i == 1955 ) return 1955;
- if(i == 1956 ) return 1956;
- if(i == 1957 ) return 1957;
- if(i == 1958 ) return 1958;
- if(i == 1959 ) return 1959;
- if(i == 1960 ) return 1960;
- if(i == 1961 ) return 1961;
- if(i == 1962 ) return 1962;
- if(i == 1963 ) return 1963;
- if(i == 1964 ) return 1964;
- if(i == 1965 ) return 1965;
- if(i == 1966 ) return 1966;
- if(i == 1967 ) return 1967;
- if(i == 1968 ) return 1968;
- if(i == 1969 ) return 1969;
- if(i == 1970 ) return 1970;
- if(i == 1971 ) return 1971;
- if(i == 1972 ) return 1972;
- if(i == 1973 ) return 1973;
- if(i == 1974 ) return 1974;
- if(i == 1975 ) return 1975;
- if(i == 1976 ) return 1976;
- if(i == 1977 ) return 1977;
- if(i == 1978 ) return 1978;
- if(i == 1979 ) return 1979;
- if(i == 1980 ) return 1980;
- if(i == 1981 ) return 1981;
- if(i == 1982 ) return 1982;
- if(i == 1983 ) return 1983;
- if(i == 1984 ) return 1984;
- if(i == 1985 ) return 1985;
- if(i == 1986 ) return 1986;
- if(i == 1987 ) return 1987;
- if(i == 1988 ) return 1988;
- if(i == 1989 ) return 1989;
- if(i == 1990 ) return 1990;
- if(i == 1991 ) return 1991;
- if(i == 1992 ) return 1992;
- if(i == 1993 ) return 1993;
- if(i == 1994 ) return 1994;
- if(i == 1995 ) return 1995;
- if(i == 1996 ) return 1996;
- if(i == 1997 ) return 1997;
- if(i == 1998 ) return 1998;
- if(i == 1999 ) return 1999;
- } finally {
- int x = 0;
- x += 1;
- x += 2;
- x += 3;
- x += 4;
- x += 5;
- x += 6;
- x += 7;
- x += 8;
- x += 9;
- }
- return 0;
- }
-}
diff --git a/langtools/test/tools/javac/ArrayCloneCodeGen.java b/langtools/test/tools/javac/ArrayCloneCodeGen.java
deleted file mode 100644
index ae496ef706a..00000000000
--- a/langtools/test/tools/javac/ArrayCloneCodeGen.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute 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 4267335
- * @summary Verify that code generated for Array.clone() with -target 1.2 passes verifier.
- * @author maddox
- *
- * @run compile -source 1.3 -target 1.2 ArrayCloneCodeGen.java
- * @run main/othervm -Xverify:all ArrayCloneCodeGen
- */
-
-public class ArrayCloneCodeGen {
-
- public static void main(String[] args) {}
-
- private String[] args = null;
-
- public String[] getArgs() {
- return (String []) (args.clone());
- }
-}
diff --git a/langtools/test/tools/javac/ClassLit.java b/langtools/test/tools/javac/ClassLit.java
index 4e26c9c43eb..9145ae23c6e 100644
--- a/langtools/test/tools/javac/ClassLit.java
+++ b/langtools/test/tools/javac/ClassLit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -26,9 +26,6 @@
* @bug 4884387
* @summary Use ldc instruction for class literals
* @author gafter
- *
- * @compile -source 1.5 -target 1.5 ClassLit.java
- * @run main ClassLit
*/
public class ClassLit {
diff --git a/langtools/test/tools/javac/ConditionalArgTypes_2.java b/langtools/test/tools/javac/ConditionalArgTypes_2.java
index b0fc6759b01..e5f5b0b7d69 100644
--- a/langtools/test/tools/javac/ConditionalArgTypes_2.java
+++ b/langtools/test/tools/javac/ConditionalArgTypes_2.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -27,7 +27,6 @@
* @summary Verify that both branches of a conditional expression must agree in type.
* @author maddox
*
- * @compile/fail -source 1.4 ConditionalArgTypes_2.java
* @compile ConditionalArgTypes_2.java
*/
diff --git a/langtools/test/tools/javac/ConditionalClass.java b/langtools/test/tools/javac/ConditionalClass.java
deleted file mode 100644
index 4628e4f3b3f..00000000000
--- a/langtools/test/tools/javac/ConditionalClass.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4949627
- * @summary javac crashes on code for new rule for semantics of ? without -source 1.5
- * @author gafter
- *
- * @compile -source 1.4 ConditionalClass.java
- */
-
-package conditional.clazz;
-
-class A{}
-class B{}
-
-public class ConditionalClass {
- void foo(){
- boolean b = false;
- Class a = b ? A.class : B.class;
- System.out.println("a is " + a.getName());
- }
-
- public static void main(String[] args)
- {
- new ConditionalClass().foo();
- }
-}
diff --git a/langtools/test/tools/javac/JsrRet.java b/langtools/test/tools/javac/JsrRet.java
index 5158b6ac49e..576f9b3b83a 100644
--- a/langtools/test/tools/javac/JsrRet.java
+++ b/langtools/test/tools/javac/JsrRet.java
@@ -27,7 +27,7 @@
* @summary StackOverflowError from javac
* @author gafter
*
- * @compile -source 1.5 -target 1.5 JsrRet.java
+ * @compile JsrRet.java
*/
package jsr.ret;
diff --git a/langtools/test/tools/javac/NoNoClassDefFoundErrorError.java b/langtools/test/tools/javac/NoNoClassDefFoundErrorError.java
deleted file mode 100644
index 1ad32d142a2..00000000000
--- a/langtools/test/tools/javac/NoNoClassDefFoundErrorError.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4313429
- * @summary Compiling .class on CLDC crashed the compiler.
- *
- * @compile/fail -source 1.4 -target 1.4 -XDfailcomplete=java.lang.NoClassDefFoundError NoNoClassDefFoundErrorError.java
- */
-
-class NoNoClassDefFoundErrorError {
- public static void main() {
- Class self = NoNoClassDefFoundErrorError.class;
- }
-}
diff --git a/langtools/test/tools/javac/T6266772.java b/langtools/test/tools/javac/T6266772.java
index 76f2f39fd88..8a5e5133766 100644
--- a/langtools/test/tools/javac/T6266772.java
+++ b/langtools/test/tools/javac/T6266772.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -26,9 +26,6 @@
* @bug 6266772
* @summary javac crashes, assertion failure in Lower.java
* @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 T6266772.java
- * @compile T6266772.java
- * @run main T6266772
*/
public class T6266772 {
diff --git a/langtools/test/tools/javac/T6557865.java b/langtools/test/tools/javac/T6557865.java
deleted file mode 100644
index 3ac154b52b2..00000000000
--- a/langtools/test/tools/javac/T6557865.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 6557865
- * @summary -source 5 -target 5 should not put ACC_SYNTHETIC on package-info
- * @author Wei Tao
- * @compile T6557865.java
- * @compile -source 5 -target 5 T6232928/package-info.java
- * @run main T6557865
- */
-
-import java.io.*;
-import java.lang.reflect.Modifier;
-
-public class T6557865 {
- public static void main(String... args) throws Exception {
- Class pkginfo_cls = Class.forName("T6232928.package-info");
- int mod = pkginfo_cls.getModifiers();
- if ((mod & 0x1000) != 0) {
- throw new AssertionError("Test failed: interface package-info shouldn't be synthetic in -target 5.");
- }
- }
-}
diff --git a/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java b/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java
index c17fd3eb6fd..bd40fc7426d 100644
--- a/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java
+++ b/langtools/test/tools/javac/UplevelFromAnonInSuperCall.java
@@ -29,7 +29,6 @@
* @author maddox (cribbed from bracha/lillibridge) gafter
*
* @compile UplevelFromAnonInSuperCall.java
- * @compile/fail -source 1.4 UplevelFromAnonInSuperCall.java
*/
class UplevelFromAnonInSuperCall {
diff --git a/langtools/test/tools/javac/annotations/neg/Dep.java b/langtools/test/tools/javac/annotations/neg/Dep.java
index 4493366af78..ff83dc761fd 100644
--- a/langtools/test/tools/javac/annotations/neg/Dep.java
+++ b/langtools/test/tools/javac/annotations/neg/Dep.java
@@ -27,7 +27,6 @@
* @summary Please add annotation Deprecated to supplant the javadoc tag
* @author gafter
*
- * @compile -source 1.4 -Xlint:-options -Xlint:dep-ann -Werror Dep.java
* @compile/fail -Xlint:dep-ann -Werror Dep.java
* @compile -Xlint:dep-ann Dep.java
*/
diff --git a/langtools/test/tools/javac/annotations/neg/MixedSource.java b/langtools/test/tools/javac/annotations/neg/MixedSource.java
deleted file mode 100644
index 30df4391289..00000000000
--- a/langtools/test/tools/javac/annotations/neg/MixedSource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 5036565
- * @summary Annotations definitions are allowed using -source 1.4 but not annotations
- * @author gafter
- *
- * @compile/fail -source 1.4 MixedSource.java
- */
-
-package mixed.source;
-
-@interface foo {}
diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java
index 22280b44109..6beae3afd8f 100644
--- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -49,7 +49,7 @@ public class ClassfileTestHelper {
File compile(File f) {
int rc = com.sun.tools.javac.Main.compile(new String[] {
- "-source", "1.8", "-g", f.getPath() });
+ "-g", f.getPath() });
if (rc != 0)
throw new Error("compilation failed. rc=" + rc);
String path = f.getPath();
diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java
index ccc3a0db1a5..d33e3d9ebe0 100644
--- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -146,7 +146,7 @@ public class NoTargetAnnotations {
}
File compileTestFile(File f) {
- int rc = com.sun.tools.javac.Main.compile(new String[] { "-XDTA:writer", "-source", "1.8", "-g", f.getPath() });
+ int rc = com.sun.tools.javac.Main.compile(new String[] { "-XDTA:writer", "-g", f.getPath() });
if (rc != 0)
throw new Error("compilation failed. rc=" + rc);
String path = f.getPath();
diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
index cb1ceafaa53..c1d226a3b78 100644
--- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Driver.java
@@ -180,7 +180,6 @@ public class Driver {
protected File compileTestFile(File f, String testClass, String... extraParams) {
List options = new ArrayList<>();
- options.addAll(Arrays.asList("-source", "1.8"));
options.addAll(Arrays.asList(extraParams));
options.add(f.getPath());
int rc = com.sun.tools.javac.Main.compile(options.toArray(new String[options.size()]));
diff --git a/langtools/test/tools/javac/api/T6265137.java b/langtools/test/tools/javac/api/T6265137.java
index 9eabaf6b605..1b86c565359 100644
--- a/langtools/test/tools/javac/api/T6265137.java
+++ b/langtools/test/tools/javac/api/T6265137.java
@@ -49,6 +49,6 @@ public class T6265137 {
String srcdir = System.getProperty("test.src");
Iterable extends JavaFileObject> files =
fm.getJavaFileObjectsFromFiles(Arrays.asList(new File(srcdir, "T6265137a.java")));
- javac.getTask(null, fm, dl, Arrays.asList("-target","1.5"), null, files).call();
+ javac.getTask(null, fm, dl, Arrays.asList("-target","9"), null, files).call();
}
}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingBool.java b/langtools/test/tools/javac/boxing/NoBoxingBool.java
deleted file mode 100644
index 5fc1d6dfb1d..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingBool.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingBool.java
- */
-
-public class NoBoxingBool {
- Boolean b = false;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingByte.java b/langtools/test/tools/javac/boxing/NoBoxingByte.java
deleted file mode 100644
index b4bbf41aa64..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingByte.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingByte.java
- */
-
-public class NoBoxingByte {
- Byte b = 0;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingChar.java b/langtools/test/tools/javac/boxing/NoBoxingChar.java
deleted file mode 100644
index f8b757e4bb5..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingChar.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingChar.java
- */
-
-public class NoBoxingChar {
- Character c = '\u0000';
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingDouble.java b/langtools/test/tools/javac/boxing/NoBoxingDouble.java
deleted file mode 100644
index faac03163e1..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingDouble.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingDouble.java
- */
-
-public class NoBoxingDouble {
- Double d = 0D;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingFloat.java b/langtools/test/tools/javac/boxing/NoBoxingFloat.java
deleted file mode 100644
index 8c81b985aa9..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingFloat.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingFloat.java
- */
-
-public class NoBoxingFloat {
- Float f = 0F;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingInt.java b/langtools/test/tools/javac/boxing/NoBoxingInt.java
deleted file mode 100644
index c66b6e33a11..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingInt.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingInt.java
- */
-
-public class NoBoxingInt {
- Integer i = 0;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingLong.java b/langtools/test/tools/javac/boxing/NoBoxingLong.java
deleted file mode 100644
index afc51498105..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingLong.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingLong.java
- */
-
-public class NoBoxingLong {
- Long l = 0L;
-}
diff --git a/langtools/test/tools/javac/boxing/NoBoxingShort.java b/langtools/test/tools/javac/boxing/NoBoxingShort.java
deleted file mode 100644
index 70c50f8defd..00000000000
--- a/langtools/test/tools/javac/boxing/NoBoxingShort.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 6177400
- * @summary Boxing allowed with -source 1.4
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 NoBoxingShort.java
- */
-
-public class NoBoxingShort {
- Short s = 0;
-}
diff --git a/langtools/test/tools/javac/classfiles/ClassVersionChecker.java b/langtools/test/tools/javac/classfiles/ClassVersionChecker.java
index f08d850d035..2fa5a7ed799 100644
--- a/langtools/test/tools/javac/classfiles/ClassVersionChecker.java
+++ b/langtools/test/tools/javac/classfiles/ClassVersionChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -37,7 +37,7 @@ import java.util.regex.*;
public class ClassVersionChecker {
int errors;
- String[] jdk = {"","1.2","1.3","1.4","1.5","1.6","1.7","1.8"};
+ String[] jdk = {"","1.6","1.7","1.8"};
File javaFile = null;
public static void main(String[] args) throws Throwable {
@@ -47,7 +47,7 @@ public class ClassVersionChecker {
void run() throws Exception {
writeTestFile();
/* Rules applicable for -source and -target combinations
- * 1. If both empty, version num is for 1.7
+ * 1. If both empty, version num is for the current release
* 2. If source is not empty and target is empty, version is based on source
* 3. If both non-empty, version is based on target
*/
@@ -57,14 +57,10 @@ public class ClassVersionChecker {
* -1 => invalid combinations
*/
int[][] ver =
- {{52, -1, -1, -1, -1, -1, -1, -1},
- {48, 46, 47, 48, 49, 50, 51, 52},
- {48, 46, 47, 48, 49, 50, 51, 52},
- {48, -1, -1, 48, 49, 50, 51, 52},
- {52, -1, -1, -1, 49, 50, 51, 52},
- {52, -1, -1, -1, -1, 50, 51, 52},
- {52, -1, -1, -1, -1, -1, 51, 52},
- {52, -1, -1, -1, -1, -1, -1, 52}};
+ {{52, -1, -1, -1},
+ {52, 50, 51, 52},
+ {52, -1, 51, 52},
+ {52, -1, -1, 52}};
// Loop to run all possible combinations of source/target values
for (int i = 0; i< ver.length; i++) {
diff --git a/langtools/test/tools/javac/enum/6384542/T6384542.java b/langtools/test/tools/javac/enum/6384542/T6384542.java
deleted file mode 100644
index 234ba485864..00000000000
--- a/langtools/test/tools/javac/enum/6384542/T6384542.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * @test /nodynamiccopyright/
- * @bug 6384542
- * @summary crash: test/tools/javac/versions/check.sh
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 1.4 -Xlint:-options T6384542.java
- * @compile/fail/ref=T6384542.out -source 1.4 -Xlint:-options -XDrawDiagnostics T6384542.java
- */
-
-import static java.lang.Math.sin;
-
-public enum A { }
-class B {
- int i = 0xCafe.BabeP1;
- List l;
- public static void main(String... args) {
- for (String arg : args) {
- System.out.println(arg);
- }
- }
- @Override
- public String toString() { return null; }
-}
-public klass C { }
diff --git a/langtools/test/tools/javac/enum/6384542/T6384542.out b/langtools/test/tools/javac/enum/6384542/T6384542.out
deleted file mode 100644
index 98480841e69..00000000000
--- a/langtools/test/tools/javac/enum/6384542/T6384542.out
+++ /dev/null
@@ -1,9 +0,0 @@
-T6384542.java:10:8: compiler.err.static.import.not.supported.in.source: 1.4
-T6384542.java:12:8: compiler.err.enums.not.supported.in.source: 1.4
-T6384542.java:14:13: compiler.err.unsupported.fp.lit: 1.4
-T6384542.java:15:9: compiler.err.generics.not.supported.in.source: 1.4
-T6384542.java:16:35: compiler.err.varargs.not.supported.in.source: 1.4
-T6384542.java:17:25: compiler.err.foreach.not.supported.in.source: 1.4
-T6384542.java:21:6: compiler.err.annotations.not.supported.in.source: 1.4
-T6384542.java:24:8: compiler.err.expected3: class, interface, enum
-8 errors
diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a.java b/langtools/test/tools/javac/enum/6384542/T6384542a.java
deleted file mode 100644
index f313b73f167..00000000000
--- a/langtools/test/tools/javac/enum/6384542/T6384542a.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * @test /nodynamiccopyright/
- * @bug 6384542
- * @summary crash: test/tools/javac/versions/check.sh
- * @author Peter von der Ah\u00e9
- * @compile/fail -source 5 T6384542a.java
- * @compile -source 1.4 T6384542a.java
- * @compile/fail/ref=T6384542a_5.out -source 5 -Xlint:-options -XDrawDiagnostics T6384542a.java
- * @compile/ref=T6384542a_1_4.out -source 1.4 -Xlint:-options -XDrawDiagnostics T6384542a.java
- */
-
-public class T6384542a {
- T6384542a enum = null;
-}
diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out b/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out
deleted file mode 100644
index 85671926d23..00000000000
--- a/langtools/test/tools/javac/enum/6384542/T6384542a_1_4.out
+++ /dev/null
@@ -1,2 +0,0 @@
-T6384542a.java:13:15: compiler.warn.enum.as.identifier
-1 warning
diff --git a/langtools/test/tools/javac/enum/6384542/T6384542a_5.out b/langtools/test/tools/javac/enum/6384542/T6384542a_5.out
deleted file mode 100644
index 0ed7fa6a530..00000000000
--- a/langtools/test/tools/javac/enum/6384542/T6384542a_5.out
+++ /dev/null
@@ -1,2 +0,0 @@
-T6384542a.java:13:15: compiler.err.enum.as.identifier
-1 error
diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier.java b/langtools/test/tools/javac/enum/EnumAsIdentifier.java
index 30bc822e49b..65392ba1a95 100644
--- a/langtools/test/tools/javac/enum/EnumAsIdentifier.java
+++ b/langtools/test/tools/javac/enum/EnumAsIdentifier.java
@@ -3,8 +3,6 @@
* @bug 8025537
* @author sogoel
* @summary enum keyword used as an identifier
- * @compile/ref=EnumAsIdentifier4.out -XDrawDiagnostics -source 1.4 EnumAsIdentifier.java
- * @compile/fail/ref=EnumAsIdentifier5.out -XDrawDiagnostics -source 1.5 EnumAsIdentifier.java
* @compile/fail/ref=EnumAsIdentifier.out -XDrawDiagnostics EnumAsIdentifier.java
*/
diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier.out b/langtools/test/tools/javac/enum/EnumAsIdentifier.out
index eeb9e842600..35051fd092c 100644
--- a/langtools/test/tools/javac/enum/EnumAsIdentifier.out
+++ b/langtools/test/tools/javac/enum/EnumAsIdentifier.out
@@ -1,2 +1,2 @@
-EnumAsIdentifier.java:13:9: compiler.err.enum.as.identifier
+EnumAsIdentifier.java:11:9: compiler.err.enum.as.identifier
1 error
diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier4.out b/langtools/test/tools/javac/enum/EnumAsIdentifier4.out
deleted file mode 100644
index 40c72a84629..00000000000
--- a/langtools/test/tools/javac/enum/EnumAsIdentifier4.out
+++ /dev/null
@@ -1,6 +0,0 @@
-- compiler.warn.source.no.bootclasspath: 1.4
-- compiler.warn.option.obsolete.source: 1.4
-- compiler.warn.option.obsolete.target: 1.4
-- compiler.warn.option.obsolete.suppression
-EnumAsIdentifier.java:13:9: compiler.warn.enum.as.identifier
-5 warnings
diff --git a/langtools/test/tools/javac/enum/EnumAsIdentifier5.out b/langtools/test/tools/javac/enum/EnumAsIdentifier5.out
deleted file mode 100644
index dead5c41a2b..00000000000
--- a/langtools/test/tools/javac/enum/EnumAsIdentifier5.out
+++ /dev/null
@@ -1,6 +0,0 @@
-- compiler.warn.source.no.bootclasspath: 1.5
-- compiler.warn.option.obsolete.source: 1.5
-- compiler.warn.option.obsolete.suppression
-EnumAsIdentifier.java:13:9: compiler.err.enum.as.identifier
-1 error
-3 warnings
diff --git a/langtools/test/tools/javac/enum/FauxEnum2.java b/langtools/test/tools/javac/enum/FauxEnum2.java
deleted file mode 100644
index dea62615a83..00000000000
--- a/langtools/test/tools/javac/enum/FauxEnum2.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 5009574
- * @summary verify java.lang.Enum can't be directly subclassed
- * @author Joseph D. Darcy
- *
- * @compile/fail -source 1.4 FauxEnum2.java
- */
-
-public class FauxEnum2 extends java.lang.Enum {
- FauxEnum2() {
- super("", 0);
- }
-}
diff --git a/langtools/test/tools/javac/foreach/T6682380.java b/langtools/test/tools/javac/foreach/T6682380.java
deleted file mode 100644
index 7c3eb84074a..00000000000
--- a/langtools/test/tools/javac/foreach/T6682380.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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 6682380 6679509
- * @summary Foreach loop with generics inside finally block crashes javac with -target 1.5
- * @author Jan Lahoda, Maurizio Cimadamore
- * @compile -source 1.5 -target 1.5 T6682380.java
- */
-
-import java.util.List;
-
-public class T6682380 {
-
- public static void main(String[] args) {
- try {
- } finally {
- List> l = null;
- T6682380>[] a = null;
- for (T6682380> e1 : l);
- for (T6682380> e2 : a);
- }
- }
-}
diff --git a/langtools/test/tools/javac/generics/BridgeRestype.java b/langtools/test/tools/javac/generics/BridgeRestype.java
deleted file mode 100644
index 2107efa4260..00000000000
--- a/langtools/test/tools/javac/generics/BridgeRestype.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4902704
- * @summary javac generates inappropriate bridge methods in -source 1.4
- * @author gafter
- *
- * @compile -source 1.4 -target 1.4 BridgeRestype.java
- * @run main BridgeRestype
- */
-
-import java.util.*;
-
-public class BridgeRestype extends Vector {
- public static void main(String[] args) {
- BridgeRestype t = new BridgeRestype();
- for (int i=0; i {
- public void foo(T t) { }
- }
- static class B extends A {
- public void foo(String t) { }
- }
-}
diff --git a/langtools/test/tools/javac/generics/compat/OverrideBridge2.java b/langtools/test/tools/javac/generics/compat/OverrideBridge2.java
deleted file mode 100644
index 57edb5348a7..00000000000
--- a/langtools/test/tools/javac/generics/compat/OverrideBridge2.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-class OverrideBridge2 {
- static class B extends OverrideBridge1.B {
- public void foo(Object o) { }
- }
-}
diff --git a/langtools/test/tools/javac/generics/compat/OverrideBridge3.java b/langtools/test/tools/javac/generics/compat/OverrideBridge3.java
deleted file mode 100644
index 87a9e2cb251..00000000000
--- a/langtools/test/tools/javac/generics/compat/OverrideBridge3.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-class OverrideBridge3 {
- static class C extends OverrideBridge2.B {
- }
-}
diff --git a/langtools/test/tools/javac/generics/compat/VisibleBridge.java b/langtools/test/tools/javac/generics/compat/VisibleBridge.java
deleted file mode 100644
index 334eb251529..00000000000
--- a/langtools/test/tools/javac/generics/compat/VisibleBridge.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4830291
- * @summary javac makes String non-backward compatible
- * @author gafter
- *
- * @compile -source 1.4 VisibleBridge.java
- */
-
-// Ensure that bridge methods are visible for maximum
-// backward compatibility.
-
-class VisibleBridge {
- static {
- Object o = "b";
- if ("a".compareTo(o) > 0) {}
- }
-}
diff --git a/langtools/test/tools/javac/limits/FinallyNesting.java b/langtools/test/tools/javac/limits/FinallyNesting.java
deleted file mode 100644
index baabd698fa5..00000000000
--- a/langtools/test/tools/javac/limits/FinallyNesting.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please 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 4739388
- * @summary regression: javac generates too much bytecode for deply nested try-finally
- * @author gafter
- *
- * @compile -source 1.4 -target 1.4 FinallyNesting.java
- */
-// Source and target 1.4 are needed for the test to pass with default memory sizes.
-class FinallyNesting {
- public static void main(String[] args) {
- int x;
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- try { x = 1; } finally {
- x = 2;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/langtools/test/tools/javac/meth/InvokeMH.java b/langtools/test/tools/javac/meth/InvokeMH.java
index 4d72b71c992..d96532825c8 100644
--- a/langtools/test/tools/javac/meth/InvokeMH.java
+++ b/langtools/test/tools/javac/meth/InvokeMH.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -27,7 +27,7 @@
* @summary Generate call sites for method handle
* @author jrose
*
- * @compile -source 7 -target 7 -XDallowTransitionalJSR292=no InvokeMH.java
+ * @compile InvokeMH.java
*/
/*
diff --git a/langtools/test/tools/javac/miranda/T4711325.java b/langtools/test/tools/javac/miranda/T4711325.java
index 4989debc58a..8889989563c 100644
--- a/langtools/test/tools/javac/miranda/T4711325.java
+++ b/langtools/test/tools/javac/miranda/T4711325.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -28,7 +28,6 @@
* @author gafter
*
* @compile T4711325.java
- * @compile/fail -source 1.4 T4711325.java
*/
interface A {
diff --git a/langtools/test/tools/javac/proprietary/WarnClass.java b/langtools/test/tools/javac/proprietary/WarnClass.java
index a3333c54104..ceeea45649e 100644
--- a/langtools/test/tools/javac/proprietary/WarnClass.java
+++ b/langtools/test/tools/javac/proprietary/WarnClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnClass.java
* @compile/fail -Werror WarnClass.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnClass.java
* @compile/fail -Werror -nowarn WarnClass.java
* @compile/fail -Werror -Xlint:none WarnClass.java
*/
diff --git a/langtools/test/tools/javac/proprietary/WarnImport.java b/langtools/test/tools/javac/proprietary/WarnImport.java
index 7d5d66a3906..7a0c25960eb 100644
--- a/langtools/test/tools/javac/proprietary/WarnImport.java
+++ b/langtools/test/tools/javac/proprietary/WarnImport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnImport.java
* @compile/fail -Werror WarnImport.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnImport.java
* @compile/fail -Werror -nowarn WarnImport.java
* @compile/fail -Werror -Xlint:none WarnImport.java
*/
diff --git a/langtools/test/tools/javac/proprietary/WarnMethod.java b/langtools/test/tools/javac/proprietary/WarnMethod.java
index 76218abf3d6..4e06100676e 100644
--- a/langtools/test/tools/javac/proprietary/WarnMethod.java
+++ b/langtools/test/tools/javac/proprietary/WarnMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnMethod.java
* @compile/fail -Werror WarnMethod.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnMethod.java
* @compile/fail -Werror -nowarn WarnMethod.java
* @compile/fail -Werror -Xlint:none WarnMethod.java
*/
diff --git a/langtools/test/tools/javac/proprietary/WarnStaticImport.java b/langtools/test/tools/javac/proprietary/WarnStaticImport.java
index a5ff4442bd4..43ce3afd8fc 100644
--- a/langtools/test/tools/javac/proprietary/WarnStaticImport.java
+++ b/langtools/test/tools/javac/proprietary/WarnStaticImport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnStaticImport.java
* @compile/fail -Werror WarnStaticImport.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnStaticImport.java
* @compile/fail -Werror -nowarn WarnStaticImport.java
* @compile/fail -Werror -Xlint:none WarnStaticImport.java
*/
diff --git a/langtools/test/tools/javac/proprietary/WarnVariable.java b/langtools/test/tools/javac/proprietary/WarnVariable.java
index 0061b1c766f..8dda29aee39 100644
--- a/langtools/test/tools/javac/proprietary/WarnVariable.java
+++ b/langtools/test/tools/javac/proprietary/WarnVariable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnVariable.java
* @compile/fail -Werror WarnVariable.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnVariable.java
* @compile/fail -Werror -nowarn WarnVariable.java
* @compile/fail -Werror -Xlint:none WarnVariable.java
*/
diff --git a/langtools/test/tools/javac/proprietary/WarnWildcard.java b/langtools/test/tools/javac/proprietary/WarnWildcard.java
index 509815eb5c5..1fee47632a2 100644
--- a/langtools/test/tools/javac/proprietary/WarnWildcard.java
+++ b/langtools/test/tools/javac/proprietary/WarnWildcard.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -28,7 +28,6 @@
* @author Peter von der Ah\u00e9
* @compile WarnWildcard.java
* @compile/fail -Werror WarnWildcard.java
- * @compile/fail -Werror -source 1.4 -nowarn WarnWildcard.java
* @compile/fail -Werror -nowarn WarnWildcard.java
* @compile/fail -Werror -Xlint:none WarnWildcard.java
*/
diff --git a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java
index f8e61e1afb4..ae6c15790c4 100644
--- a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java
+++ b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.java
@@ -25,7 +25,6 @@
* @test
* @bug 7038363
* @summary cast from object to primitive should be for source >= 1.7
- * @compile/fail/ref=CastObjectToPrimitiveTest.out -XDrawDiagnostics -Xlint:-options -source 5 CastObjectToPrimitiveTest.java
* @compile/fail/ref=CastObjectToPrimitiveTest.out -XDrawDiagnostics -Xlint:-options -source 6 CastObjectToPrimitiveTest.java
* @compile CastObjectToPrimitiveTest.java
*/
diff --git a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out
index f57047f99d9..80f12654b24 100644
--- a/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out
+++ b/langtools/test/tools/javac/types/CastObjectToPrimitiveTest.out
@@ -1,2 +1,2 @@
-CastObjectToPrimitiveTest.java:36:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int)
+CastObjectToPrimitiveTest.java:35:23: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, int)
1 error
From 35f1475d20c2d4fd43929b65740cd84471ac160b Mon Sep 17 00:00:00 2001
From: Igor Veresov
Date: Mon, 10 Mar 2014 11:09:02 -0700
Subject: [PATCH 047/116] 8025644:
java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java
fails with TestData$OfRef): failure java.lang.AssertionError: expected [true]
but found [false]
In GraphKit::gen_checkcast() provide only exact superklass to GraphKit::maybe_cast_profiled_receiver()
Reviewed-by: kvn, roland
---
hotspot/src/share/vm/opto/graphKit.cpp | 38 +++++++++++++++-----------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp
index d11e4ff5ccf..d9fcfb2cb91 100644
--- a/hotspot/src/share/vm/opto/graphKit.cpp
+++ b/hotspot/src/share/vm/opto/graphKit.cpp
@@ -3007,22 +3007,28 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
}
Node* cast_obj = NULL;
- const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
- // We may not have profiling here or it may not help us. If we have
- // a speculative type use it to perform an exact cast.
- ciKlass* spec_obj_type = obj_type->speculative_type();
- if (spec_obj_type != NULL ||
- (data != NULL &&
- // Counter has never been decremented (due to cast failure).
- // ...This is a reasonable thing to expect. It is true of
- // all casts inserted by javac to implement generic types.
- data->as_CounterData()->count() >= 0)) {
- cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
- if (cast_obj != NULL) {
- if (failure_control != NULL) // failure is now impossible
- (*failure_control) = top();
- // adjust the type of the phi to the exact klass:
- phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR));
+ if (tk->klass_is_exact()) {
+ // The following optimization tries to statically cast the speculative type of the object
+ // (for example obtained during profiling) to the type of the superklass and then do a
+ // dynamic check that the type of the object is what we expect. To work correctly
+ // for checkcast and aastore the type of superklass should be exact.
+ const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
+ // We may not have profiling here or it may not help us. If we have
+ // a speculative type use it to perform an exact cast.
+ ciKlass* spec_obj_type = obj_type->speculative_type();
+ if (spec_obj_type != NULL ||
+ (data != NULL &&
+ // Counter has never been decremented (due to cast failure).
+ // ...This is a reasonable thing to expect. It is true of
+ // all casts inserted by javac to implement generic types.
+ data->as_CounterData()->count() >= 0)) {
+ cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
+ if (cast_obj != NULL) {
+ if (failure_control != NULL) // failure is now impossible
+ (*failure_control) = top();
+ // adjust the type of the phi to the exact klass:
+ phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR));
+ }
}
}
From 13a70d932e0a9a3282d01f0aaf9dc8a876a737e4 Mon Sep 17 00:00:00 2001
From: David Chase
Date: Tue, 11 Mar 2014 13:38:32 -0400
Subject: [PATCH 048/116] 8028037: [parfait] warnings from b114 for
hotspot.src.share.vm
Insert null check for one warning; other warning handled in parfait config
Reviewed-by: kvn
---
hotspot/src/share/vm/opto/multnode.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hotspot/src/share/vm/opto/multnode.cpp b/hotspot/src/share/vm/opto/multnode.cpp
index 300f6246369..1da4b7789f4 100644
--- a/hotspot/src/share/vm/opto/multnode.cpp
+++ b/hotspot/src/share/vm/opto/multnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -194,7 +194,9 @@ bool ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) {
}
}
- ProjNode* other_proj = iff->proj_out(1-_con)->as_Proj();
+ ProjNode* other_proj = iff->proj_out(1-_con);
+ if (other_proj == NULL) // Should never happen, but make Parfait happy.
+ return false;
if (other_proj->is_uncommon_trap_proj(reason)) {
assert(reason == Deoptimization::Reason_none ||
Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list");
From 1a1f9f0871d36fc5ae320d000348a0772733e082 Mon Sep 17 00:00:00 2001
From: Christian Thalinger
Date: Tue, 11 Mar 2014 14:54:47 -0700
Subject: [PATCH 049/116] 8037043: put Method flag bits in predictable
positions
Reviewed-by: kvn, coleenp
---
hotspot/src/share/vm/oops/method.hpp | 61 ++++++++++++++++------
hotspot/src/share/vm/runtime/vmStructs.cpp | 6 +++
2 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp
index 931b08b5264..98598dbeeff 100644
--- a/hotspot/src/share/vm/oops/method.hpp
+++ b/hotspot/src/share/vm/oops/method.hpp
@@ -108,12 +108,16 @@ class Method : public Metadata {
#endif
u2 _method_size; // size of this object
u1 _intrinsic_id; // vmSymbols::intrinsic_id (0 == _none)
- u1 _jfr_towrite : 1, // Flags
- _caller_sensitive : 1,
- _force_inline : 1,
- _hidden : 1,
- _dont_inline : 1,
- : 3;
+
+ // Flags
+ enum Flags {
+ _jfr_towrite = 1 << 0,
+ _caller_sensitive = 1 << 1,
+ _force_inline = 1 << 2,
+ _dont_inline = 1 << 3,
+ _hidden = 1 << 4
+ };
+ u1 _flags;
#ifndef PRODUCT
int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging)
@@ -759,16 +763,41 @@ class Method : public Metadata {
void init_intrinsic_id(); // updates from _none if a match
static vmSymbols::SID klass_id_for_intrinsics(Klass* holder);
- bool jfr_towrite() { return _jfr_towrite; }
- void set_jfr_towrite(bool x) { _jfr_towrite = x; }
- bool caller_sensitive() { return _caller_sensitive; }
- void set_caller_sensitive(bool x) { _caller_sensitive = x; }
- bool force_inline() { return _force_inline; }
- void set_force_inline(bool x) { _force_inline = x; }
- bool dont_inline() { return _dont_inline; }
- void set_dont_inline(bool x) { _dont_inline = x; }
- bool is_hidden() { return _hidden; }
- void set_hidden(bool x) { _hidden = x; }
+ bool jfr_towrite() {
+ return (_flags & _jfr_towrite) != 0;
+ }
+ void set_jfr_towrite(bool x) {
+ _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite);
+ }
+
+ bool caller_sensitive() {
+ return (_flags & _caller_sensitive) != 0;
+ }
+ void set_caller_sensitive(bool x) {
+ _flags = x ? (_flags | _caller_sensitive) : (_flags & ~_caller_sensitive);
+ }
+
+ bool force_inline() {
+ return (_flags & _force_inline) != 0;
+ }
+ void set_force_inline(bool x) {
+ _flags = x ? (_flags | _force_inline) : (_flags & ~_force_inline);
+ }
+
+ bool dont_inline() {
+ return (_flags & _dont_inline) != 0;
+ }
+ void set_dont_inline(bool x) {
+ _flags = x ? (_flags | _dont_inline) : (_flags & ~_dont_inline);
+ }
+
+ bool is_hidden() {
+ return (_flags & _hidden) != 0;
+ }
+ void set_hidden(bool x) {
+ _flags = x ? (_flags | _hidden) : (_flags & ~_hidden);
+ }
+
ConstMethod::MethodType method_type() const {
return _constMethod->method_type();
}
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index 7044dc9b2b7..2475de0480a 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -2336,6 +2336,12 @@ typedef TwoOopHashtable SymbolTwoOopHashtable;
/* ConstMethod anon-enum */ \
/********************************/ \
\
+ declare_constant(Method::_jfr_towrite) \
+ declare_constant(Method::_caller_sensitive) \
+ declare_constant(Method::_force_inline) \
+ declare_constant(Method::_dont_inline) \
+ declare_constant(Method::_hidden) \
+ \
declare_constant(ConstMethod::_has_linenumber_table) \
declare_constant(ConstMethod::_has_checked_exceptions) \
declare_constant(ConstMethod::_has_localvariable_table) \
From 768beb9a23d3d82a04c8c8bf323b33309e256493 Mon Sep 17 00:00:00 2001
From: Igor Veresov
Date: Wed, 12 Mar 2014 11:24:26 -0700
Subject: [PATCH 050/116] 8031321: Support Intel bit manipulation instructions
Add support for BMI1 instructions
Reviewed-by: kvn, roland
---
hotspot/src/cpu/x86/vm/assembler_x86.cpp | 138 +++++++++
hotspot/src/cpu/x86/vm/assembler_x86.hpp | 49 +++
hotspot/src/cpu/x86/vm/globals_x86.hpp | 6 +
hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 42 ++-
hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 19 +-
hotspot/src/cpu/x86/vm/x86_32.ad | 358 ++++++++++++++++++++++
hotspot/src/cpu/x86/vm/x86_64.ad | 258 ++++++++++++++++
hotspot/src/share/vm/adlc/formssel.cpp | 12 +-
hotspot/src/share/vm/opto/matcher.cpp | 107 +++++++
hotspot/src/share/vm/opto/matcher.hpp | 3 +
hotspot/test/compiler/codegen/BMI1.java | 301 ++++++++++++++++++
11 files changed, 1280 insertions(+), 13 deletions(-)
create mode 100644 hotspot/test/compiler/codegen/BMI1.java
diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
index 49cc9ed65cf..d305ac18537 100644
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
@@ -1089,6 +1089,21 @@ void Assembler::andl(Register dst, Register src) {
emit_arith(0x23, 0xC0, dst, src);
}
+void Assembler::andnl(Register dst, Register src1, Register src2) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode(dst, src1, src2);
+ emit_int8((unsigned char)0xF2);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::andnl(Register dst, Register src1, Address src2) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38(dst, src1, src2);
+ emit_int8((unsigned char)0xF2);
+ emit_operand(dst, src2);
+}
+
void Assembler::bsfl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
emit_int8(0x0F);
@@ -1110,6 +1125,51 @@ void Assembler::bswapl(Register reg) { // bswap
emit_int8((unsigned char)(0xC8 | encode));
}
+void Assembler::blsil(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode(rbx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsil(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38(rbx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rbx, src);
+}
+
+void Assembler::blsmskl(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode(rdx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsmskl(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38(rdx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rdx, src);
+}
+
+void Assembler::blsrl(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode(rcx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsrl(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38(rcx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rcx, src);
+}
+
void Assembler::call(Label& L, relocInfo::relocType rtype) {
// suspect disp32 is always good
int operand = LP64_ONLY(disp32_operand) NOT_LP64(imm_operand);
@@ -2878,6 +2938,24 @@ void Assembler::testl(Register dst, Address src) {
emit_operand(dst, src);
}
+void Assembler::tzcntl(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ emit_int8((unsigned char)0xF3);
+ int encode = prefix_and_encode(dst->encoding(), src->encoding());
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBC);
+ emit_int8((unsigned char)0xC0 | encode);
+}
+
+void Assembler::tzcntq(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported");
+ emit_int8((unsigned char)0xF3);
+ int encode = prefixq_and_encode(dst->encoding(), src->encoding());
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBC);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
void Assembler::ucomisd(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_simd_arith_nonds(0x2E, dst, src, VEX_SIMD_66);
@@ -4837,6 +4915,21 @@ void Assembler::andq(Register dst, Register src) {
emit_arith(0x23, 0xC0, dst, src);
}
+void Assembler::andnq(Register dst, Register src1, Register src2) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode_q(dst, src1, src2);
+ emit_int8((unsigned char)0xF2);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::andnq(Register dst, Register src1, Address src2) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38_q(dst, src1, src2);
+ emit_int8((unsigned char)0xF2);
+ emit_operand(dst, src2);
+}
+
void Assembler::bsfq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
emit_int8(0x0F);
@@ -4858,6 +4951,51 @@ void Assembler::bswapq(Register reg) {
emit_int8((unsigned char)(0xC8 | encode));
}
+void Assembler::blsiq(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode_q(rbx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsiq(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38_q(rbx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rbx, src);
+}
+
+void Assembler::blsmskq(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode_q(rdx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsmskq(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38_q(rdx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rdx, src);
+}
+
+void Assembler::blsrq(Register dst, Register src) {
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ int encode = vex_prefix_0F38_and_encode_q(rcx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::blsrq(Register dst, Address src) {
+ InstructionMark im(this);
+ assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported");
+ vex_prefix_0F38_q(rcx, dst, src);
+ emit_int8((unsigned char)0xF3);
+ emit_operand(rcx, src);
+}
+
void Assembler::cdqq() {
prefix(REX_W);
emit_int8((unsigned char)0x99);
diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp
index 1ad66bd6a95..95ca231cef4 100644
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp
@@ -590,10 +590,35 @@ private:
vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, false, vector256);
}
+ void vex_prefix_0F38(Register dst, Register nds, Address src) {
+ bool vex_w = false;
+ bool vector256 = false;
+ vex_prefix(src, nds->encoding(), dst->encoding(),
+ VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256);
+ }
+
+ void vex_prefix_0F38_q(Register dst, Register nds, Address src) {
+ bool vex_w = true;
+ bool vector256 = false;
+ vex_prefix(src, nds->encoding(), dst->encoding(),
+ VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256);
+ }
int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc,
VexSimdPrefix pre, VexOpcode opc,
bool vex_w, bool vector256);
+ int vex_prefix_0F38_and_encode(Register dst, Register nds, Register src) {
+ bool vex_w = false;
+ bool vector256 = false;
+ return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(),
+ VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256);
+ }
+ int vex_prefix_0F38_and_encode_q(Register dst, Register nds, Register src) {
+ bool vex_w = true;
+ bool vector256 = false;
+ return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(),
+ VEX_SIMD_NONE, VEX_OPCODE_0F_38, vex_w, vector256);
+ }
int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src,
VexSimdPrefix pre, bool vector256 = false,
VexOpcode opc = VEX_OPCODE_0F) {
@@ -897,6 +922,27 @@ private:
void andq(Register dst, Address src);
void andq(Register dst, Register src);
+ // BMI instructions
+ void andnl(Register dst, Register src1, Register src2);
+ void andnl(Register dst, Register src1, Address src2);
+ void andnq(Register dst, Register src1, Register src2);
+ void andnq(Register dst, Register src1, Address src2);
+
+ void blsil(Register dst, Register src);
+ void blsil(Register dst, Address src);
+ void blsiq(Register dst, Register src);
+ void blsiq(Register dst, Address src);
+
+ void blsmskl(Register dst, Register src);
+ void blsmskl(Register dst, Address src);
+ void blsmskq(Register dst, Register src);
+ void blsmskq(Register dst, Address src);
+
+ void blsrl(Register dst, Register src);
+ void blsrl(Register dst, Address src);
+ void blsrq(Register dst, Register src);
+ void blsrq(Register dst, Address src);
+
void bsfl(Register dst, Register src);
void bsrl(Register dst, Register src);
@@ -1574,6 +1620,9 @@ private:
void testq(Register dst, int32_t imm32);
void testq(Register dst, Register src);
+ // BMI - count trailing zeros
+ void tzcntl(Register dst, Register src);
+ void tzcntq(Register dst, Register src);
// Unordered Compare Scalar Double-Precision Floating-Point Values and set EFLAGS
void ucomisd(XMMRegister dst, Address src);
diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp
index e82c192901b..f29e5d6e322 100644
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp
@@ -135,5 +135,11 @@ define_pd_global(uintx, TypeProfileLevel, 111);
\
product(bool, UseCountLeadingZerosInstruction, false, \
"Use count leading zeros instruction") \
+ \
+ product(bool, UseCountTrailingZerosInstruction, false, \
+ "Use count trailing zeros instruction") \
+ \
+ product(bool, UseBMI1Instructions, false, \
+ "Use BMI instructions")
#endif // CPU_X86_VM_GLOBALS_X86_HPP
diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
index de38b4a3a53..b949e4e2998 100644
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
@@ -429,7 +429,7 @@ void VM_Version::get_processor_features() {
}
char buf[256];
- jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping,
(supports_cmov() ? ", cmov" : ""),
@@ -455,7 +455,9 @@ void VM_Version::get_processor_features() {
(supports_ht() ? ", ht": ""),
(supports_tsc() ? ", tsc": ""),
(supports_tscinv_bit() ? ", tscinvbit": ""),
- (supports_tscinv() ? ", tscinv": ""));
+ (supports_tscinv() ? ", tscinv": ""),
+ (supports_bmi1() ? ", bmi1" : ""),
+ (supports_bmi2() ? ", bmi2" : ""));
_features_str = strdup(buf);
// UseSSE is set to the smaller of what hardware supports and what
@@ -600,13 +602,6 @@ void VM_Version::get_processor_features() {
}
}
- // Use count leading zeros count instruction if available.
- if (supports_lzcnt()) {
- if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) {
- UseCountLeadingZerosInstruction = true;
- }
- }
-
// some defaults for AMD family 15h
if ( cpu_family() == 0x15 ) {
// On family 15h processors default is no sw prefetch
@@ -692,6 +687,35 @@ void VM_Version::get_processor_features() {
}
#endif // COMPILER2
+ // Use count leading zeros count instruction if available.
+ if (supports_lzcnt()) {
+ if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) {
+ UseCountLeadingZerosInstruction = true;
+ }
+ } else if (UseCountLeadingZerosInstruction) {
+ warning("lzcnt instruction is not available on this CPU");
+ FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false);
+ }
+
+ if (supports_bmi1()) {
+ if (FLAG_IS_DEFAULT(UseBMI1Instructions)) {
+ UseBMI1Instructions = true;
+ }
+ } else if (UseBMI1Instructions) {
+ warning("BMI1 instructions are not available on this CPU");
+ FLAG_SET_DEFAULT(UseBMI1Instructions, false);
+ }
+
+ // Use count trailing zeros instruction if available
+ if (supports_bmi1()) {
+ if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) {
+ UseCountTrailingZerosInstruction = UseBMI1Instructions;
+ }
+ } else if (UseCountTrailingZerosInstruction) {
+ warning("tzcnt instruction is not available on this CPU");
+ FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false);
+ }
+
// Use population count instruction if available.
if (supports_popcnt()) {
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
index 86e9b662d52..07d64451870 100644
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
@@ -141,7 +141,8 @@ public:
struct {
uint32_t LahfSahf : 1,
CmpLegacy : 1,
- : 4,
+ : 3,
+ lzcnt_intel : 1,
lzcnt : 1,
sse4a : 1,
misalignsse : 1,
@@ -251,7 +252,9 @@ protected:
CPU_AVX2 = (1 << 18),
CPU_AES = (1 << 19),
CPU_ERMS = (1 << 20), // enhanced 'rep movsb/stosb' instructions
- CPU_CLMUL = (1 << 21) // carryless multiply for CRC
+ CPU_CLMUL = (1 << 21), // carryless multiply for CRC
+ CPU_BMI1 = (1 << 22),
+ CPU_BMI2 = (1 << 23)
} cpuFeatureFlags;
enum {
@@ -423,6 +426,8 @@ protected:
if (_cpuid_info.sef_cpuid7_ebx.bits.avx2 != 0)
result |= CPU_AVX2;
}
+ if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0)
+ result |= CPU_BMI1;
if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0)
result |= CPU_TSC;
if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0)
@@ -444,6 +449,13 @@ protected:
if (_cpuid_info.ext_cpuid1_ecx.bits.sse4a != 0)
result |= CPU_SSE4A;
}
+ // Intel features.
+ if(is_intel()) {
+ if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
+ result |= CPU_BMI2;
+ if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
+ result |= CPU_LZCNT;
+ }
return result;
}
@@ -560,7 +572,8 @@ public:
static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; }
static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; }
static bool supports_clmul() { return (_cpuFeatures & CPU_CLMUL) != 0; }
-
+ static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; }
+ static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; }
// Intel features
static bool is_intel_family_core() { return is_intel() &&
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad
index 8948682a99f..c4820db3b07 100644
--- a/hotspot/src/cpu/x86/vm/x86_32.ad
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad
@@ -5163,6 +5163,19 @@ instruct countLeadingZerosL_bsr(rRegI dst, eRegL src, eFlagsReg cr) %{
%}
instruct countTrailingZerosI(rRegI dst, rRegI src, eFlagsReg cr) %{
+ predicate(UseCountTrailingZerosInstruction);
+ match(Set dst (CountTrailingZerosI src));
+ effect(KILL cr);
+
+ format %{ "TZCNT $dst, $src\t# count trailing zeros (int)" %}
+ ins_encode %{
+ __ tzcntl($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, eFlagsReg cr) %{
+ predicate(!UseCountTrailingZerosInstruction);
match(Set dst (CountTrailingZerosI src));
effect(KILL cr);
@@ -5182,6 +5195,30 @@ instruct countTrailingZerosI(rRegI dst, rRegI src, eFlagsReg cr) %{
%}
instruct countTrailingZerosL(rRegI dst, eRegL src, eFlagsReg cr) %{
+ predicate(UseCountTrailingZerosInstruction);
+ match(Set dst (CountTrailingZerosL src));
+ effect(TEMP dst, KILL cr);
+
+ format %{ "TZCNT $dst, $src.lo\t# count trailing zeros (long) \n\t"
+ "JNC done\n\t"
+ "TZCNT $dst, $src.hi\n\t"
+ "ADD $dst, 32\n"
+ "done:" %}
+ ins_encode %{
+ Register Rdst = $dst$$Register;
+ Register Rsrc = $src$$Register;
+ Label done;
+ __ tzcntl(Rdst, Rsrc);
+ __ jccb(Assembler::carryClear, done);
+ __ tzcntl(Rdst, HIGH_FROM_LOW(Rsrc));
+ __ addl(Rdst, BitsPerInt);
+ __ bind(done);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct countTrailingZerosL_bsf(rRegI dst, eRegL src, eFlagsReg cr) %{
+ predicate(!UseCountTrailingZerosInstruction);
match(Set dst (CountTrailingZerosL src));
effect(TEMP dst, KILL cr);
@@ -8027,6 +8064,123 @@ instruct andI_mem_imm(memory dst, immI src, eFlagsReg cr) %{
ins_pipe( ialu_mem_imm );
%}
+// BMI1 instructions
+instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, eFlagsReg cr) %{
+ match(Set dst (AndI (XorI src1 minus_1) src2));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "ANDNL $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnl($dst$$Register, $src1$$Register, $src2$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, eFlagsReg cr) %{
+ match(Set dst (AndI (XorI src1 minus_1) (LoadI src2) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "ANDNL $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnl($dst$$Register, $src1$$Register, $src2$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI0 imm_zero, eFlagsReg cr) %{
+ match(Set dst (AndI (SubI imm_zero src) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "BLSIL $dst, $src" %}
+
+ ins_encode %{
+ __ blsil($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsiI_rReg_mem(rRegI dst, memory src, immI0 imm_zero, eFlagsReg cr) %{
+ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "BLSIL $dst, $src" %}
+
+ ins_encode %{
+ __ blsil($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (XorI (AddI src minus_1) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "BLSMSKL $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskl($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "BLSMSKL $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskl($dst$$Register, $src$$Address);
+ %}
+
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (AndI (AddI src minus_1) src) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "BLSRL $dst, $src" %}
+
+ ins_encode %{
+ __ blsrl($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "BLSRL $dst, $src" %}
+
+ ins_encode %{
+ __ blsrl($dst$$Register, $src$$Address);
+ %}
+
+ ins_pipe(ialu_reg_mem);
+%}
+
// Or Instructions
// Or Register with Register
instruct orI_eReg(rRegI dst, rRegI src, eFlagsReg cr) %{
@@ -8649,6 +8803,210 @@ instruct andL_eReg_mem(eRegL dst, load_long_memory mem, eFlagsReg cr) %{
ins_pipe( ialu_reg_long_mem );
%}
+// BMI1 instructions
+instruct andnL_eReg_eReg_eReg(eRegL dst, eRegL src1, eRegL src2, immL_M1 minus_1, eFlagsReg cr) %{
+ match(Set dst (AndL (XorL src1 minus_1) src2));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ format %{ "ANDNL $dst.lo, $src1.lo, $src2.lo\n\t"
+ "ANDNL $dst.hi, $src1.hi, $src2.hi"
+ %}
+
+ ins_encode %{
+ Register Rdst = $dst$$Register;
+ Register Rsrc1 = $src1$$Register;
+ Register Rsrc2 = $src2$$Register;
+ __ andnl(Rdst, Rsrc1, Rsrc2);
+ __ andnl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc1), HIGH_FROM_LOW(Rsrc2));
+ %}
+ ins_pipe(ialu_reg_reg_long);
+%}
+
+instruct andnL_eReg_eReg_mem(eRegL dst, eRegL src1, memory src2, immL_M1 minus_1, eFlagsReg cr) %{
+ match(Set dst (AndL (XorL src1 minus_1) (LoadL src2) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ ins_cost(125);
+ format %{ "ANDNL $dst.lo, $src1.lo, $src2\n\t"
+ "ANDNL $dst.hi, $src1.hi, $src2+4"
+ %}
+
+ ins_encode %{
+ Register Rdst = $dst$$Register;
+ Register Rsrc1 = $src1$$Register;
+ Address src2_hi = Address::make_raw($src2$$base, $src2$$index, $src2$$scale, $src2$$disp + 4, relocInfo::none);
+
+ __ andnl(Rdst, Rsrc1, $src2$$Address);
+ __ andnl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc1), src2_hi);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsiL_eReg_eReg(eRegL dst, eRegL src, immL0 imm_zero, eFlagsReg cr) %{
+ match(Set dst (AndL (SubL imm_zero src) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ format %{ "MOVL $dst.hi, 0\n\t"
+ "BLSIL $dst.lo, $src.lo\n\t"
+ "JNZ done\n\t"
+ "BLSIL $dst.hi, $src.hi\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Register Rsrc = $src$$Register;
+ __ movl(HIGH_FROM_LOW(Rdst), 0);
+ __ blsil(Rdst, Rsrc);
+ __ jccb(Assembler::notZero, done);
+ __ blsil(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc));
+ __ bind(done);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsiL_eReg_mem(eRegL dst, memory src, immL0 imm_zero, eFlagsReg cr) %{
+ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ ins_cost(125);
+ format %{ "MOVL $dst.hi, 0\n\t"
+ "BLSIL $dst.lo, $src\n\t"
+ "JNZ done\n\t"
+ "BLSIL $dst.hi, $src+4\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none);
+
+ __ movl(HIGH_FROM_LOW(Rdst), 0);
+ __ blsil(Rdst, $src$$Address);
+ __ jccb(Assembler::notZero, done);
+ __ blsil(HIGH_FROM_LOW(Rdst), src_hi);
+ __ bind(done);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskL_eReg_eReg(eRegL dst, eRegL src, immL_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (XorL (AddL src minus_1) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ format %{ "MOVL $dst.hi, 0\n\t"
+ "BLSMSKL $dst.lo, $src.lo\n\t"
+ "JNC done\n\t"
+ "BLSMSKL $dst.hi, $src.hi\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Register Rsrc = $src$$Register;
+ __ movl(HIGH_FROM_LOW(Rdst), 0);
+ __ blsmskl(Rdst, Rsrc);
+ __ jccb(Assembler::carryClear, done);
+ __ blsmskl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc));
+ __ bind(done);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsmskL_eReg_mem(eRegL dst, memory src, immL_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ ins_cost(125);
+ format %{ "MOVL $dst.hi, 0\n\t"
+ "BLSMSKL $dst.lo, $src\n\t"
+ "JNC done\n\t"
+ "BLSMSKL $dst.hi, $src+4\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none);
+
+ __ movl(HIGH_FROM_LOW(Rdst), 0);
+ __ blsmskl(Rdst, $src$$Address);
+ __ jccb(Assembler::carryClear, done);
+ __ blsmskl(HIGH_FROM_LOW(Rdst), src_hi);
+ __ bind(done);
+ %}
+
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsrL_eReg_eReg(eRegL dst, eRegL src, immL_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (AndL (AddL src minus_1) src) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ format %{ "MOVL $dst.hi, $src.hi\n\t"
+ "BLSRL $dst.lo, $src.lo\n\t"
+ "JNC done\n\t"
+ "BLSRL $dst.hi, $src.hi\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Register Rsrc = $src$$Register;
+ __ movl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc));
+ __ blsrl(Rdst, Rsrc);
+ __ jccb(Assembler::carryClear, done);
+ __ blsrl(HIGH_FROM_LOW(Rdst), HIGH_FROM_LOW(Rsrc));
+ __ bind(done);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsrL_eReg_mem(eRegL dst, memory src, immL_M1 minus_1, eFlagsReg cr)
+%{
+ match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr, TEMP dst);
+
+ ins_cost(125);
+ format %{ "MOVL $dst.hi, $src+4\n\t"
+ "BLSRL $dst.lo, $src\n\t"
+ "JNC done\n\t"
+ "BLSRL $dst.hi, $src+4\n"
+ "done:"
+ %}
+
+ ins_encode %{
+ Label done;
+ Register Rdst = $dst$$Register;
+ Address src_hi = Address::make_raw($src$$base, $src$$index, $src$$scale, $src$$disp + 4, relocInfo::none);
+ __ movl(HIGH_FROM_LOW(Rdst), src_hi);
+ __ blsrl(Rdst, $src$$Address);
+ __ jccb(Assembler::carryClear, done);
+ __ blsrl(HIGH_FROM_LOW(Rdst), src_hi);
+ __ bind(done);
+ %}
+
+ ins_pipe(ialu_reg_mem);
+%}
+
// Or Long Register with Register
instruct orl_eReg(eRegL dst, eRegL src, eFlagsReg cr) %{
match(Set dst (OrL dst src));
diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad
index b10f920793e..cebc37cc25c 100644
--- a/hotspot/src/cpu/x86/vm/x86_64.ad
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad
@@ -6022,6 +6022,19 @@ instruct countLeadingZerosL_bsr(rRegI dst, rRegL src, rFlagsReg cr) %{
%}
instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{
+ predicate(UseCountTrailingZerosInstruction);
+ match(Set dst (CountTrailingZerosI src));
+ effect(KILL cr);
+
+ format %{ "tzcntl $dst, $src\t# count trailing zeros (int)" %}
+ ins_encode %{
+ __ tzcntl($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct countTrailingZerosI_bsf(rRegI dst, rRegI src, rFlagsReg cr) %{
+ predicate(!UseCountTrailingZerosInstruction);
match(Set dst (CountTrailingZerosI src));
effect(KILL cr);
@@ -6041,6 +6054,19 @@ instruct countTrailingZerosI(rRegI dst, rRegI src, rFlagsReg cr) %{
%}
instruct countTrailingZerosL(rRegI dst, rRegL src, rFlagsReg cr) %{
+ predicate(UseCountTrailingZerosInstruction);
+ match(Set dst (CountTrailingZerosL src));
+ effect(KILL cr);
+
+ format %{ "tzcntq $dst, $src\t# count trailing zeros (long)" %}
+ ins_encode %{
+ __ tzcntq($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct countTrailingZerosL_bsf(rRegI dst, rRegL src, rFlagsReg cr) %{
+ predicate(!UseCountTrailingZerosInstruction);
match(Set dst (CountTrailingZerosL src));
effect(KILL cr);
@@ -8622,6 +8648,122 @@ instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr)
ins_pipe(ialu_mem_imm);
%}
+// BMI1 instructions
+instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, rFlagsReg cr) %{
+ match(Set dst (AndI (XorI src1 minus_1) (LoadI src2)));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "andnl $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnl($dst$$Register, $src1$$Register, $src2$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, rFlagsReg cr) %{
+ match(Set dst (AndI (XorI src1 minus_1) src2));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "andnl $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnl($dst$$Register, $src1$$Register, $src2$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI0 imm_zero, rFlagsReg cr) %{
+ match(Set dst (AndI (SubI imm_zero src) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsil $dst, $src" %}
+
+ ins_encode %{
+ __ blsil($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsiI_rReg_mem(rRegI dst, memory src, immI0 imm_zero, rFlagsReg cr) %{
+ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsil $dst, $src" %}
+
+ ins_encode %{
+ __ blsil($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsmskl $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskl($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (XorI (AddI src minus_1) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsmskl $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskl($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (AndI (AddI src minus_1) src) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsrl $dst, $src" %}
+
+ ins_encode %{
+ __ blsrl($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsrl $dst, $src" %}
+
+ ins_encode %{
+ __ blsrl($dst$$Register, $src$$Address);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
// Or Instructions
// Or Register with Register
instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr)
@@ -8853,6 +8995,122 @@ instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr)
ins_pipe(ialu_mem_imm);
%}
+// BMI1 instructions
+instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1, rFlagsReg cr) %{
+ match(Set dst (AndL (XorL src1 minus_1) (LoadL src2)));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "andnq $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnq($dst$$Register, $src1$$Register, $src2$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1, rFlagsReg cr) %{
+ match(Set dst (AndL (XorL src1 minus_1) src2));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "andnq $dst, $src1, $src2" %}
+
+ ins_encode %{
+ __ andnq($dst$$Register, $src1$$Register, $src2$$Register);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{
+ match(Set dst (AndL (SubL imm_zero src) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsiq $dst, $src" %}
+
+ ins_encode %{
+ __ blsiq($dst$$Register, $src$$Register);
+ %}
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{
+ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) ));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsiq $dst, $src" %}
+
+ ins_encode %{
+ __ blsiq($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsmskq $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskq($dst$$Register, $src$$Address);
+ %}
+ ins_pipe(ialu_reg_mem);
+%}
+
+instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (XorL (AddL src minus_1) src));
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsmskq $dst, $src" %}
+
+ ins_encode %{
+ __ blsmskq($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (AndL (AddL src minus_1) src) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ format %{ "blsrq $dst, $src" %}
+
+ ins_encode %{
+ __ blsrq($dst$$Register, $src$$Register);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
+instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr)
+%{
+ match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) );
+ predicate(UseBMI1Instructions);
+ effect(KILL cr);
+
+ ins_cost(125);
+ format %{ "blsrq $dst, $src" %}
+
+ ins_encode %{
+ __ blsrq($dst$$Register, $src$$Address);
+ %}
+
+ ins_pipe(ialu_reg);
+%}
+
// Or Instructions
// Or Register with Register
instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr)
diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp
index 614aaf1553a..df58c5746de 100644
--- a/hotspot/src/share/vm/adlc/formssel.cpp
+++ b/hotspot/src/share/vm/adlc/formssel.cpp
@@ -660,6 +660,7 @@ int InstructForm::memory_operand(FormDict &globals) const {
int USE_of_memory = 0;
int DEF_of_memory = 0;
const char* last_memory_DEF = NULL; // to test DEF/USE pairing in asserts
+ const char* last_memory_USE = NULL;
Component *unique = NULL;
Component *comp = NULL;
ComponentList &components = (ComponentList &)_components;
@@ -681,7 +682,16 @@ int InstructForm::memory_operand(FormDict &globals) const {
assert(0 == strcmp(last_memory_DEF, comp->_name), "every memory DEF is followed by a USE of the same name");
last_memory_DEF = NULL;
}
- USE_of_memory++;
+ // Handles same memory being used multiple times in the case of BMI1 instructions.
+ if (last_memory_USE != NULL) {
+ if (strcmp(comp->_name, last_memory_USE) != 0) {
+ USE_of_memory++;
+ }
+ } else {
+ USE_of_memory++;
+ }
+ last_memory_USE = comp->_name;
+
if (DEF_of_memory == 0) // defs take precedence
unique = comp;
} else {
diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp
index 03ee1dc8086..f263a3c5044 100644
--- a/hotspot/src/share/vm/opto/matcher.cpp
+++ b/hotspot/src/share/vm/opto/matcher.cpp
@@ -1922,6 +1922,105 @@ OptoReg::Name Matcher::find_receiver( bool is_outgoing ) {
return OptoReg::as_OptoReg(regs.first());
}
+// This function identifies sub-graphs in which a 'load' node is
+// input to two different nodes, and such that it can be matched
+// with BMI instructions like blsi, blsr, etc.
+// Example : for b = -a[i] & a[i] can be matched to blsi r32, m32.
+// The graph is (AndL (SubL Con0 LoadL*) LoadL*), where LoadL*
+// refers to the same node.
+#ifdef X86
+// Match the generic fused operations pattern (op1 (op2 Con{ConType} mop) mop)
+// This is a temporary solution until we make DAGs expressible in ADL.
+template
+class FusedPatternMatcher {
+ Node* _op1_node;
+ Node* _mop_node;
+ int _con_op;
+
+ static int match_next(Node* n, int next_op, int next_op_idx) {
+ if (n->in(1) == NULL || n->in(2) == NULL) {
+ return -1;
+ }
+
+ if (next_op_idx == -1) { // n is commutative, try rotations
+ if (n->in(1)->Opcode() == next_op) {
+ return 1;
+ } else if (n->in(2)->Opcode() == next_op) {
+ return 2;
+ }
+ } else {
+ assert(next_op_idx > 0 && next_op_idx <= 2, "Bad argument index");
+ if (n->in(next_op_idx)->Opcode() == next_op) {
+ return next_op_idx;
+ }
+ }
+ return -1;
+ }
+public:
+ FusedPatternMatcher(Node* op1_node, Node *mop_node, int con_op) :
+ _op1_node(op1_node), _mop_node(mop_node), _con_op(con_op) { }
+
+ bool match(int op1, int op1_op2_idx, // op1 and the index of the op1->op2 edge, -1 if op1 is commutative
+ int op2, int op2_con_idx, // op2 and the index of the op2->con edge, -1 if op2 is commutative
+ typename ConType::NativeType con_value) {
+ if (_op1_node->Opcode() != op1) {
+ return false;
+ }
+ if (_mop_node->outcnt() > 2) {
+ return false;
+ }
+ op1_op2_idx = match_next(_op1_node, op2, op1_op2_idx);
+ if (op1_op2_idx == -1) {
+ return false;
+ }
+ // Memory operation must be the other edge
+ int op1_mop_idx = (op1_op2_idx & 1) + 1;
+
+ // Check that the mop node is really what we want
+ if (_op1_node->in(op1_mop_idx) == _mop_node) {
+ Node *op2_node = _op1_node->in(op1_op2_idx);
+ if (op2_node->outcnt() > 1) {
+ return false;
+ }
+ assert(op2_node->Opcode() == op2, "Should be");
+ op2_con_idx = match_next(op2_node, _con_op, op2_con_idx);
+ if (op2_con_idx == -1) {
+ return false;
+ }
+ // Memory operation must be the other edge
+ int op2_mop_idx = (op2_con_idx & 1) + 1;
+ // Check that the memory operation is the same node
+ if (op2_node->in(op2_mop_idx) == _mop_node) {
+ // Now check the constant
+ const Type* con_type = op2_node->in(op2_con_idx)->bottom_type();
+ if (con_type != Type::TOP && ConType::as_self(con_type)->get_con() == con_value) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+};
+
+
+bool Matcher::is_bmi_pattern(Node *n, Node *m) {
+ if (n != NULL && m != NULL) {
+ if (m->Opcode() == Op_LoadI) {
+ FusedPatternMatcher bmii(n, m, Op_ConI);
+ return bmii.match(Op_AndI, -1, Op_SubI, 1, 0) ||
+ bmii.match(Op_AndI, -1, Op_AddI, -1, -1) ||
+ bmii.match(Op_XorI, -1, Op_AddI, -1, -1);
+ } else if (m->Opcode() == Op_LoadL) {
+ FusedPatternMatcher bmil(n, m, Op_ConL);
+ return bmil.match(Op_AndL, -1, Op_SubL, 1, 0) ||
+ bmil.match(Op_AndL, -1, Op_AddL, -1, -1) ||
+ bmil.match(Op_XorL, -1, Op_AddL, -1, -1);
+ }
+ }
+ return false;
+}
+#endif // X86
+
// A method-klass-holder may be passed in the inline_cache_reg
// and then expanded into the inline_cache_reg and a method_oop register
// defined in ad_.cpp
@@ -2077,6 +2176,14 @@ void Matcher::find_shared( Node *n ) {
set_shared(m->in(AddPNode::Base)->in(1));
}
+ // if 'n' and 'm' are part of a graph for BMI instruction, clone this node.
+#ifdef X86
+ if (UseBMI1Instructions && is_bmi_pattern(n, m)) {
+ mstack.push(m, Visit);
+ continue;
+ }
+#endif
+
// Clone addressing expressions as they are "free" in memory access instructions
if( mem_op && i == MemNode::Address && mop == Op_AddP ) {
// Some inputs for address expression are not put on stack
diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp
index 38eeca40290..66d4a0adab9 100644
--- a/hotspot/src/share/vm/opto/matcher.hpp
+++ b/hotspot/src/share/vm/opto/matcher.hpp
@@ -79,6 +79,9 @@ class Matcher : public PhaseTransform {
// Find shared Nodes, or Nodes that otherwise are Matcher roots
void find_shared( Node *n );
+#ifdef X86
+ bool is_bmi_pattern(Node *n, Node *m);
+#endif
// Debug and profile information for nodes in old space:
GrowableArray* _old_node_note_array;
diff --git a/hotspot/test/compiler/codegen/BMI1.java b/hotspot/test/compiler/codegen/BMI1.java
new file mode 100644
index 00000000000..ada9cf06c34
--- /dev/null
+++ b/hotspot/test/compiler/codegen/BMI1.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8031321
+ * @summary Support BMI1 instructions on x86/x64
+ * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileCommand=compileonly,BMITests.* BMI1
+ *
+ */
+
+class MemI {
+ public int x;
+ public MemI(int x) { this.x = x; }
+}
+
+class MemL {
+ public long x;
+ public MemL(long x) { this.x = x; }
+}
+
+class BMITests {
+ static int andnl(int src1, int src2) {
+ return ~src1 & src2;
+ }
+ static long andnq(long src1, long src2) {
+ return ~src1 & src2;
+ }
+ static int andnl(int src1, MemI src2) {
+ return ~src1 & src2.x;
+ }
+ static long andnq(long src1, MemL src2) {
+ return ~src1 & src2.x;
+ }
+ static int blsil(int src1) {
+ return src1 & -src1;
+ }
+ static long blsiq(long src1) {
+ return src1 & -src1;
+ }
+ static int blsil(MemI src1) {
+ return src1.x & -src1.x;
+ }
+ static long blsiq(MemL src1) {
+ return src1.x & -src1.x;
+ }
+ static int blsmskl(int src1) {
+ return (src1 - 1) ^ src1;
+ }
+ static long blsmskq(long src1) {
+ return (src1 - 1) ^ src1;
+ }
+ static int blsmskl(MemI src1) {
+ return (src1.x - 1) ^ src1.x;
+ }
+ static long blsmskq(MemL src1) {
+ return (src1.x - 1) ^ src1.x;
+ }
+ static int blsrl(int src1) {
+ return (src1 - 1) & src1;
+ }
+ static long blsrq(long src1) {
+ return (src1 - 1) & src1;
+ }
+ static int blsrl(MemI src1) {
+ return (src1.x - 1) & src1.x;
+ }
+ static long blsrq(MemL src1) {
+ return (src1.x - 1) & src1.x;
+ }
+ static int lzcntl(int src1) {
+ return Integer.numberOfLeadingZeros(src1);
+ }
+ static int lzcntq(long src1) {
+ return Long.numberOfLeadingZeros(src1);
+ }
+ static int tzcntl(int src1) {
+ return Integer.numberOfTrailingZeros(src1);
+ }
+ static int tzcntq(long src1) {
+ return Long.numberOfTrailingZeros(src1);
+ }
+}
+
+public class BMI1 {
+ private final static int ITERATIONS = 1000000;
+
+ public static void main(String[] args) {
+ int ix = 0x01234567;
+ int iy = 0x89abcdef;
+ MemI imy = new MemI(iy);
+ long lx = 0x0123456701234567L;
+ long ly = 0x89abcdef89abcdefL;
+ MemL lmy = new MemL(ly);
+
+ { // match(Set dst (AndI (XorI src1 minus_1) src2))
+ int z = BMITests.andnl(ix, iy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.andnl(ix, iy);
+ if (ii != z) {
+ throw new Error("andnl with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (XorL src1 minus_1) src2))
+ long z = BMITests.andnq(lx, ly);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.andnq(lx, ly);
+ if (ll != z) {
+ throw new Error("andnq with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndI (XorI src1 minus_1) (LoadI src2)))
+ int z = BMITests.andnl(ix, imy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.andnl(ix, imy);
+ if (ii != z) {
+ throw new Error("andnl with memory failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (XorL src1 minus_1) (LoadL src2)))
+ long z = BMITests.andnq(lx, lmy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.andnq(lx, lmy);
+ if (ll != z) {
+ throw new Error("andnq with memory failed");
+ }
+ }
+ }
+ { // match(Set dst (AndI (SubI imm_zero src) src))
+ int z = BMITests.blsil(ix);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsil(ix);
+ if (ii != z) {
+ throw new Error("blsil with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (SubL imm_zero src) src))
+ long z = BMITests.blsiq(lx);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsiq(lx);
+ if (ll != z) {
+ throw new Error("blsiq with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) ))
+ int z = BMITests.blsil(imy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsil(imy);
+ if (ii != z) {
+ throw new Error("blsil with memory failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) ))
+ long z = BMITests.blsiq(lmy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsiq(lmy);
+ if (ll != z) {
+ throw new Error("blsiq with memory failed");
+ }
+ }
+ }
+
+ { // match(Set dst (XorI (AddI src minus_1) src))
+ int z = BMITests.blsmskl(ix);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsmskl(ix);
+ if (ii != z) {
+ throw new Error("blsmskl with register failed");
+ }
+ }
+ }
+ { // match(Set dst (XorL (AddL src minus_1) src))
+ long z = BMITests.blsmskq(lx);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsmskq(lx);
+ if (ll != z) {
+ throw new Error("blsmskq with register failed");
+ }
+ }
+ }
+ { // match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) )
+ int z = BMITests.blsmskl(imy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsmskl(imy);
+ if (ii != z) {
+ throw new Error("blsmskl with memory failed");
+ }
+ }
+ }
+ { // match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) )
+ long z = BMITests.blsmskq(lmy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsmskq(lmy);
+ if (ll != z) {
+ throw new Error("blsmskq with memory failed");
+ }
+ }
+ }
+
+ { // match(Set dst (AndI (AddI src minus_1) src) )
+ int z = BMITests.blsrl(ix);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsrl(ix);
+ if (ii != z) {
+ throw new Error("blsrl with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (AddL src minus_1) src) )
+ long z = BMITests.blsrq(lx);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsrq(lx);
+ if (ll != z) {
+ throw new Error("blsrq with register failed");
+ }
+ }
+ }
+ { // match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) )
+ int z = BMITests.blsrl(imy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.blsrl(imy);
+ if (ii != z) {
+ throw new Error("blsrl with memory failed");
+ }
+ }
+ }
+ { // match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) )
+ long z = BMITests.blsrq(lmy);
+ for (int i = 0; i < ITERATIONS; i++) {
+ long ll = BMITests.blsrq(lmy);
+ if (ll != z) {
+ throw new Error("blsrq with memory failed");
+ }
+ }
+ }
+
+ {
+ int z = BMITests.lzcntl(ix);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.lzcntl(ix);
+ if (ii != z) {
+ throw new Error("lzcntl failed");
+ }
+ }
+ }
+ {
+ int z = BMITests.lzcntq(lx);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.lzcntq(lx);
+ if (ii != z) {
+ throw new Error("lzcntq failed");
+ }
+ }
+ }
+
+ {
+ int z = BMITests.tzcntl(ix);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.tzcntl(ix);
+ if (ii != z) {
+ throw new Error("tzcntl failed");
+ }
+ }
+ }
+ {
+ int z = BMITests.tzcntq(lx);
+ for (int i = 0; i < ITERATIONS; i++) {
+ int ii = BMITests.tzcntq(lx);
+ if (ii != z) {
+ throw new Error("tzcntq failed");
+ }
+ }
+ }
+ }
+}
From faad7883f26dcc7b43efc99cc417844f2142e823 Mon Sep 17 00:00:00 2001
From: Axel Siebenborn
Date: Mon, 10 Mar 2014 12:58:02 +0100
Subject: [PATCH 051/116] 8036976: PPC64: implement the template interpreter
Co-authored-by: Martin Doerr
Reviewed-by: kvn, coleenp
---
hotspot/make/aix/Makefile | 4 +
hotspot/make/linux/Makefile | 4 +
hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp | 6 +-
hotspot/src/cpu/ppc/vm/frame_ppc.cpp | 30 +-
hotspot/src/cpu/ppc/vm/frame_ppc.hpp | 96 +-
hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp | 75 +-
hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp | 1731 ++++++-
hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp | 218 +-
hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp | 58 +-
hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp | 14 +-
.../src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp | 6 +-
hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 25 +-
hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 24 +-
.../cpu/ppc/vm/macroAssembler_ppc.inline.hpp | 21 +-
hotspot/src/cpu/ppc/vm/register_ppc.hpp | 32 +-
hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 43 +-
hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 22 +-
.../vm/templateInterpreterGenerator_ppc.hpp | 44 +
.../cpu/ppc/vm/templateInterpreter_ppc.cpp | 1813 ++++++++
.../cpu/ppc/vm/templateInterpreter_ppc.hpp | 41 +
.../src/cpu/ppc/vm/templateTable_ppc_64.cpp | 4082 +++++++++++++++++
.../src/cpu/ppc/vm/templateTable_ppc_64.hpp | 38 +
.../share/vm/interpreter/templateTable.hpp | 3 +
23 files changed, 8327 insertions(+), 103 deletions(-)
create mode 100644 hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp
create mode 100644 hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
create mode 100644 hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
create mode 100644 hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp
create mode 100644 hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp
diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile
index 19bab5494bc..79bcf7880ac 100644
--- a/hotspot/make/aix/Makefile
+++ b/hotspot/make/aix/Makefile
@@ -70,6 +70,10 @@ ifndef CC_INTERP
FORCE_TIERED=1
endif
endif
+# C1 is not ported on ppc64(le), so we cannot build a tiered VM:
+ifneq (,$(filter $(ARCH),ppc64 pp64le))
+ FORCE_TIERED=0
+endif
ifdef LP64
ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","")
diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile
index 0820c254612..8321f8e15db 100644
--- a/hotspot/make/linux/Makefile
+++ b/hotspot/make/linux/Makefile
@@ -66,6 +66,10 @@ ifndef CC_INTERP
FORCE_TIERED=1
endif
endif
+# C1 is not ported on ppc64(le), so we cannot build a tiered VM:
+ifneq (,$(filter $(ARCH),ppc64 pp64le))
+ FORCE_TIERED=0
+endif
ifdef LP64
ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","")
diff --git a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
index 44c09d9c30a..5cf5a6a6573 100644
--- a/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/cppInterpreter_ppc.cpp
@@ -1353,9 +1353,9 @@ address CppInterpreterGenerator::generate_native_entry(void) {
// notify here, we'll drop it on the floor.
__ notify_method_exit(true/*native method*/,
- ilgl /*illegal state (not used for native methods)*/);
-
-
+ ilgl /*illegal state (not used for native methods)*/,
+ InterpreterMacroAssembler::NotifyJVMTI,
+ false /*check_exceptions*/);
//=============================================================================
// Handle exceptions
diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp
index 1cd2c6a0a5b..6df316d1b87 100644
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,10 +42,6 @@
#include "runtime/vframeArray.hpp"
#endif
-#ifndef CC_INTERP
-#error "CC_INTERP must be defined on PPC64"
-#endif
-
#ifdef ASSERT
void RegisterMap::check_location_valid() {
}
@@ -89,7 +85,10 @@ frame frame::sender_for_entry_frame(RegisterMap *map) const {
frame frame::sender_for_interpreter_frame(RegisterMap *map) const {
// Pass callers initial_caller_sp as unextended_sp.
- return frame(sender_sp(), sender_pc(), (intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp);
+ return frame(sender_sp(), sender_pc(),
+ CC_INTERP_ONLY((intptr_t*)((parent_ijava_frame_abi *)callers_abi())->initial_caller_sp)
+ NOT_CC_INTERP((intptr_t*)get_ijava_state()->sender_sp)
+ );
}
frame frame::sender_for_compiled_frame(RegisterMap *map) const {
@@ -183,6 +182,9 @@ BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result)
interpreterState istate = get_interpreterState();
address lresult = (address)istate + in_bytes(BytecodeInterpreter::native_lresult_offset());
address fresult = (address)istate + in_bytes(BytecodeInterpreter::native_fresult_offset());
+#else
+ address lresult = (address)&(get_ijava_state()->lresult);
+ address fresult = (address)&(get_ijava_state()->fresult);
#endif
switch (method->result_type()) {
@@ -259,7 +261,21 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
values.describe(frame_no, (intptr_t*)&(istate->_native_fresult), " native_fresult");
values.describe(frame_no, (intptr_t*)&(istate->_native_lresult), " native_lresult");
#else
- Unimplemented();
+#define DESCRIBE_ADDRESS(name) \
+ values.describe(frame_no, (intptr_t*)&(get_ijava_state()->name), #name);
+
+ DESCRIBE_ADDRESS(method);
+ DESCRIBE_ADDRESS(locals);
+ DESCRIBE_ADDRESS(monitors);
+ DESCRIBE_ADDRESS(cpoolCache);
+ DESCRIBE_ADDRESS(bcp);
+ DESCRIBE_ADDRESS(esp);
+ DESCRIBE_ADDRESS(mdx);
+ DESCRIBE_ADDRESS(top_frame_sp);
+ DESCRIBE_ADDRESS(sender_sp);
+ DESCRIBE_ADDRESS(oop_tmp);
+ DESCRIBE_ADDRESS(lresult);
+ DESCRIBE_ADDRESS(fresult);
#endif
}
}
diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
index b0a350252ad..f327d2ce424 100644
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,10 +29,6 @@
#include "runtime/synchronizer.hpp"
#include "utilities/top.hpp"
-#ifndef CC_INTERP
-#error "CC_INTERP must be defined on PPC64"
-#endif
-
// C frame layout on PPC-64.
//
// In this figure the stack grows upwards, while memory grows
@@ -197,7 +193,85 @@
#define _spill_nonvolatiles_neg(_component) \
(int)(-frame::spill_nonvolatiles_size + offset_of(frame::spill_nonvolatiles, _component))
- // Frame layout for the Java interpreter on PPC64.
+
+
+#ifndef CC_INTERP
+ // Frame layout for the Java template interpreter on PPC64.
+ //
+ // Diffs to the CC_INTERP are marked with 'X'.
+ //
+ // TOP_IJAVA_FRAME:
+ //
+ // 0 [TOP_IJAVA_FRAME_ABI]
+ // alignment (optional)
+ // [operand stack]
+ // [monitors] (optional)
+ // X[IJAVA_STATE]
+ // note: own locals are located in the caller frame.
+ //
+ // PARENT_IJAVA_FRAME:
+ //
+ // 0 [PARENT_IJAVA_FRAME_ABI]
+ // alignment (optional)
+ // [callee's Java result]
+ // [callee's locals w/o arguments]
+ // [outgoing arguments]
+ // [used part of operand stack w/o arguments]
+ // [monitors] (optional)
+ // X[IJAVA_STATE]
+ //
+
+ struct parent_ijava_frame_abi : abi_minframe {
+ };
+
+ enum {
+ parent_ijava_frame_abi_size = sizeof(parent_ijava_frame_abi)
+ };
+
+#define _parent_ijava_frame_abi(_component) \
+ (offset_of(frame::parent_ijava_frame_abi, _component))
+
+ struct top_ijava_frame_abi : abi_reg_args {
+ };
+
+ enum {
+ top_ijava_frame_abi_size = sizeof(top_ijava_frame_abi)
+ };
+
+#define _top_ijava_frame_abi(_component) \
+ (offset_of(frame::top_ijava_frame_abi, _component))
+
+ struct ijava_state {
+#ifdef ASSERT
+ uint64_t ijava_reserved; // Used for assertion.
+ uint64_t ijava_reserved2; // Inserted for alignment.
+#endif
+ uint64_t method;
+ uint64_t locals;
+ uint64_t monitors;
+ uint64_t cpoolCache;
+ uint64_t bcp;
+ uint64_t esp;
+ uint64_t mdx;
+ uint64_t top_frame_sp; // Maybe define parent_frame_abi and move there.
+ uint64_t sender_sp;
+ // Slots only needed for native calls. Maybe better to move elsewhere.
+ uint64_t oop_tmp;
+ uint64_t lresult;
+ uint64_t fresult;
+ // Aligned to frame::alignment_in_bytes (16).
+ };
+
+ enum {
+ ijava_state_size = sizeof(ijava_state)
+ };
+
+#define _ijava_state_neg(_component) \
+ (int) (-frame::ijava_state_size + offset_of(frame::ijava_state, _component))
+
+#else // CC_INTERP:
+
+ // Frame layout for the Java C++ interpreter on PPC64.
//
// This frame layout provides a C-like frame for every Java frame.
//
@@ -300,6 +374,8 @@
#define _top_ijava_frame_abi(_component) \
(offset_of(frame::top_ijava_frame_abi, _component))
+#endif // CC_INTERP
+
// ENTRY_FRAME
struct entry_frame_locals {
@@ -423,6 +499,14 @@
#ifdef CC_INTERP
// Additional interface for interpreter frames:
inline interpreterState get_interpreterState() const;
+#else
+ inline ijava_state* get_ijava_state() const;
+ // Some convenient register frame setters/getters for deoptimization.
+ inline intptr_t* interpreter_frame_esp() const;
+ inline void interpreter_frame_set_cpcache(ConstantPoolCache* cp);
+ inline void interpreter_frame_set_esp(intptr_t* esp);
+ inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp);
+ inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp);
#endif // CC_INTERP
// Size of a monitor in bytes.
diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp
index 2dadd6c69eb..8e46363eac9 100644
--- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp
+++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,6 @@
#ifndef CPU_PPC_VM_FRAME_PPC_INLINE_HPP
#define CPU_PPC_VM_FRAME_PPC_INLINE_HPP
-#ifndef CC_INTERP
-#error "CC_INTERP must be defined on PPC64"
-#endif
-
// Inline functions for ppc64 frames:
// Find codeblob and set deopt_state.
@@ -199,6 +195,75 @@ inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
interpreterState istate = get_interpreterState();
return &istate->_constants;
}
+
+#else // !CC_INTERP
+
+// Template Interpreter frame value accessors.
+
+inline frame::ijava_state* frame::get_ijava_state() const {
+ return (ijava_state*) ((uintptr_t)fp() - ijava_state_size);
+}
+
+inline intptr_t** frame::interpreter_frame_locals_addr() const {
+ return (intptr_t**) &(get_ijava_state()->locals);
+}
+inline intptr_t* frame::interpreter_frame_bcx_addr() const {
+ return (intptr_t*) &(get_ijava_state()->bcp);
+}
+inline intptr_t* frame::interpreter_frame_mdx_addr() const {
+ return (intptr_t*) &(get_ijava_state()->mdx);
+}
+// Pointer beyond the "oldest/deepest" BasicObjectLock on stack.
+inline BasicObjectLock* frame::interpreter_frame_monitor_end() const {
+ return (BasicObjectLock *) get_ijava_state()->monitors;
+}
+
+inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const {
+ return (BasicObjectLock *) get_ijava_state();
+}
+
+// SAPJVM ASc 2012-11-21. Return register stack slot addr at which currently interpreted method is found
+inline Method** frame::interpreter_frame_method_addr() const {
+ return (Method**) &(get_ijava_state()->method);
+}
+inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const {
+ return (ConstantPoolCache**) &(get_ijava_state()->cpoolCache);
+}
+inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const {
+ return (ConstantPoolCache**) &(get_ijava_state()->cpoolCache);
+}
+
+inline oop* frame::interpreter_frame_temp_oop_addr() const {
+ return (oop *) &(get_ijava_state()->oop_tmp);
+}
+inline intptr_t* frame::interpreter_frame_esp() const {
+ return (intptr_t*) get_ijava_state()->esp;
+}
+
+// Convenient setters
+inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* end) { get_ijava_state()->monitors = (intptr_t) end;}
+inline void frame::interpreter_frame_set_cpcache(ConstantPoolCache* cp) { *frame::interpreter_frame_cpoolcache_addr() = cp; }
+inline void frame::interpreter_frame_set_esp(intptr_t* esp) { get_ijava_state()->esp = (intptr_t) esp; }
+inline void frame::interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp) { get_ijava_state()->top_frame_sp = (intptr_t) top_frame_sp; }
+inline void frame::interpreter_frame_set_sender_sp(intptr_t* sender_sp) { get_ijava_state()->sender_sp = (intptr_t) sender_sp; }
+
+inline intptr_t* frame::interpreter_frame_expression_stack() const {
+ return (intptr_t*)interpreter_frame_monitor_end() - 1;
+}
+
+inline jint frame::interpreter_frame_expression_stack_direction() {
+ return -1;
+}
+
+// top of expression stack
+inline intptr_t* frame::interpreter_frame_tos_address() const {
+ return ((intptr_t*) get_ijava_state()->esp) + Interpreter::stackElementWords;
+}
+
+inline intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
+ return &interpreter_frame_tos_address()[offset];
+}
+
#endif // CC_INTERP
inline int frame::interpreter_frame_monitor_size() {
diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp
index 5d135199b7e..f71acaca095 100644
--- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp
+++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "asm/macroAssembler.inline.hpp"
#include "interp_masm_ppc_64.hpp"
#include "interpreter/interpreterRuntime.hpp"
+#include "prims/jvmtiThreadState.hpp"
#ifdef PRODUCT
#define BLOCK_COMMENT(str) // nothing
@@ -45,6 +46,691 @@ void InterpreterMacroAssembler::null_check_throw(Register a, int offset, Registe
MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry);
}
+void InterpreterMacroAssembler::branch_to_entry(address entry, Register Rscratch) {
+ assert(entry, "Entry must have been generated by now");
+ if (is_within_range_of_b(entry, pc())) {
+ b(entry);
+ } else {
+ load_const_optimized(Rscratch, entry, R0);
+ mtctr(Rscratch);
+ bctr();
+ }
+}
+
+#ifndef CC_INTERP
+
+void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr) {
+ Register bytecode = R12_scratch2;
+ if (bcp_incr != 0) {
+ lbzu(bytecode, bcp_incr, R14_bcp);
+ } else {
+ lbz(bytecode, 0, R14_bcp);
+ }
+
+ dispatch_Lbyte_code(state, bytecode, Interpreter::dispatch_table(state));
+}
+
+void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) {
+ // Load current bytecode.
+ Register bytecode = R12_scratch2;
+ lbz(bytecode, 0, R14_bcp);
+ dispatch_Lbyte_code(state, bytecode, table);
+}
+
+// Dispatch code executed in the prolog of a bytecode which does not do it's
+// own dispatch. The dispatch address is computed and placed in R24_dispatch_addr.
+void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) {
+ Register bytecode = R12_scratch2;
+ lbz(bytecode, bcp_incr, R14_bcp);
+
+ load_dispatch_table(R24_dispatch_addr, Interpreter::dispatch_table(state));
+
+ sldi(bytecode, bytecode, LogBytesPerWord);
+ ldx(R24_dispatch_addr, R24_dispatch_addr, bytecode);
+}
+
+// Dispatch code executed in the epilog of a bytecode which does not do it's
+// own dispatch. The dispatch address in R24_dispatch_addr is used for the
+// dispatch.
+void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) {
+ mtctr(R24_dispatch_addr);
+ addi(R14_bcp, R14_bcp, bcp_incr);
+ bctr();
+}
+
+void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) {
+ assert(scratch_reg != R0, "can't use R0 as scratch_reg here");
+ if (JvmtiExport::can_pop_frame()) {
+ Label L;
+
+ // Check the "pending popframe condition" flag in the current thread.
+ lwz(scratch_reg, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Initiate popframe handling only if it is not already being
+ // processed. If the flag has the popframe_processing bit set, it
+ // means that this code is called *during* popframe handling - we
+ // don't want to reenter.
+ andi_(R0, scratch_reg, JavaThread::popframe_pending_bit);
+ beq(CCR0, L);
+
+ andi_(R0, scratch_reg, JavaThread::popframe_processing_bit);
+ bne(CCR0, L);
+
+ // Call the Interpreter::remove_activation_preserving_args_entry()
+ // func to get the address of the same-named entrypoint in the
+ // generated interpreter code.
+ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*,
+ Interpreter::remove_activation_preserving_args_entry),
+ relocInfo::none);
+
+ // Jump to Interpreter::_remove_activation_preserving_args_entry.
+ mtctr(R3_RET);
+ bctr();
+
+ align(32, 12);
+ bind(L);
+ }
+}
+
+void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg) {
+ const Register Rthr_state_addr = scratch_reg;
+ if (JvmtiExport::can_force_early_return()) {
+ Label Lno_early_ret;
+ ld(Rthr_state_addr, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
+ cmpdi(CCR0, Rthr_state_addr, 0);
+ beq(CCR0, Lno_early_ret);
+
+ lwz(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rthr_state_addr);
+ cmpwi(CCR0, R0, JvmtiThreadState::earlyret_pending);
+ bne(CCR0, Lno_early_ret);
+
+ // Jump to Interpreter::_earlyret_entry.
+ lwz(R3_ARG1, in_bytes(JvmtiThreadState::earlyret_tos_offset()), Rthr_state_addr);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry));
+ mtlr(R3_RET);
+ blr();
+
+ align(32, 12);
+ bind(Lno_early_ret);
+ }
+}
+
+void InterpreterMacroAssembler::load_earlyret_value(TosState state, Register Rscratch1) {
+ const Register RjvmtiState = Rscratch1;
+ const Register Rscratch2 = R0;
+
+ ld(RjvmtiState, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
+ li(Rscratch2, 0);
+
+ switch (state) {
+ case atos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState);
+ std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_oop_offset()), RjvmtiState);
+ break;
+ case ltos: ld(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
+ break;
+ case btos: // fall through
+ case ctos: // fall through
+ case stos: // fall through
+ case itos: lwz(R17_tos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
+ break;
+ case ftos: lfs(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
+ break;
+ case dtos: lfd(F15_ftos, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
+ break;
+ case vtos: break;
+ default : ShouldNotReachHere();
+ }
+
+ // Clean up tos value in the jvmti thread state.
+ std(Rscratch2, in_bytes(JvmtiThreadState::earlyret_value_offset()), RjvmtiState);
+ // Set tos state field to illegal value.
+ li(Rscratch2, ilgl);
+ stw(Rscratch2, in_bytes(JvmtiThreadState::earlyret_tos_offset()), RjvmtiState);
+}
+
+// Common code to dispatch and dispatch_only.
+// Dispatch value in Lbyte_code and increment Lbcp.
+
+void InterpreterMacroAssembler::load_dispatch_table(Register dst, address* table) {
+ address table_base = (address)Interpreter::dispatch_table((TosState)0);
+ intptr_t table_offs = (intptr_t)table - (intptr_t)table_base;
+ if (is_simm16(table_offs)) {
+ addi(dst, R25_templateTableBase, (int)table_offs);
+ } else {
+ load_const_optimized(dst, table, R0);
+ }
+}
+
+void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify) {
+ if (verify) {
+ unimplemented("dispatch_Lbyte_code: verify"); // See Sparc Implementation to implement this
+ }
+
+#ifdef FAST_DISPATCH
+ unimplemented("dispatch_Lbyte_code FAST_DISPATCH");
+#else
+ assert_different_registers(bytecode, R11_scratch1);
+
+ // Calc dispatch table address.
+ load_dispatch_table(R11_scratch1, table);
+
+ sldi(R12_scratch2, bytecode, LogBytesPerWord);
+ ldx(R11_scratch1, R11_scratch1, R12_scratch2);
+
+ // Jump off!
+ mtctr(R11_scratch1);
+ bctr();
+#endif
+}
+
+void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) {
+ sldi(Rrecv_dst, Rparam_count, Interpreter::logStackElementSize);
+ ldx(Rrecv_dst, Rrecv_dst, R15_esp);
+}
+
+// helpers for expression stack
+
+void InterpreterMacroAssembler::pop_i(Register r) {
+ lwzu(r, Interpreter::stackElementSize, R15_esp);
+}
+
+void InterpreterMacroAssembler::pop_ptr(Register r) {
+ ldu(r, Interpreter::stackElementSize, R15_esp);
+}
+
+void InterpreterMacroAssembler::pop_l(Register r) {
+ ld(r, Interpreter::stackElementSize, R15_esp);
+ addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize);
+}
+
+void InterpreterMacroAssembler::pop_f(FloatRegister f) {
+ lfsu(f, Interpreter::stackElementSize, R15_esp);
+}
+
+void InterpreterMacroAssembler::pop_d(FloatRegister f) {
+ lfd(f, Interpreter::stackElementSize, R15_esp);
+ addi(R15_esp, R15_esp, 2 * Interpreter::stackElementSize);
+}
+
+void InterpreterMacroAssembler::push_i(Register r) {
+ stw(r, 0, R15_esp);
+ addi(R15_esp, R15_esp, - Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_ptr(Register r) {
+ std(r, 0, R15_esp);
+ addi(R15_esp, R15_esp, - Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_l(Register r) {
+ std(r, - Interpreter::stackElementSize, R15_esp);
+ addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_f(FloatRegister f) {
+ stfs(f, 0, R15_esp);
+ addi(R15_esp, R15_esp, - Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_d(FloatRegister f) {
+ stfd(f, - Interpreter::stackElementSize, R15_esp);
+ addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_2ptrs(Register first, Register second) {
+ std(first, 0, R15_esp);
+ std(second, -Interpreter::stackElementSize, R15_esp);
+ addi(R15_esp, R15_esp, - 2 * Interpreter::stackElementSize );
+}
+
+void InterpreterMacroAssembler::push_l_pop_d(Register l, FloatRegister d) {
+ std(l, 0, R15_esp);
+ lfd(d, 0, R15_esp);
+}
+
+void InterpreterMacroAssembler::push_d_pop_l(FloatRegister d, Register l) {
+ stfd(d, 0, R15_esp);
+ ld(l, 0, R15_esp);
+}
+
+void InterpreterMacroAssembler::push(TosState state) {
+ switch (state) {
+ case atos: push_ptr(); break;
+ case btos:
+ case ctos:
+ case stos:
+ case itos: push_i(); break;
+ case ltos: push_l(); break;
+ case ftos: push_f(); break;
+ case dtos: push_d(); break;
+ case vtos: /* nothing to do */ break;
+ default : ShouldNotReachHere();
+ }
+}
+
+void InterpreterMacroAssembler::pop(TosState state) {
+ switch (state) {
+ case atos: pop_ptr(); break;
+ case btos:
+ case ctos:
+ case stos:
+ case itos: pop_i(); break;
+ case ltos: pop_l(); break;
+ case ftos: pop_f(); break;
+ case dtos: pop_d(); break;
+ case vtos: /* nothing to do */ break;
+ default : ShouldNotReachHere();
+ }
+ verify_oop(R17_tos, state);
+}
+
+void InterpreterMacroAssembler::empty_expression_stack() {
+ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize);
+}
+
+void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(int bcp_offset,
+ Register Rdst,
+ signedOrNot is_signed) {
+ // Read Java big endian format.
+ if (is_signed == Signed) {
+ lha(Rdst, bcp_offset, R14_bcp);
+ } else {
+ lhz(Rdst, bcp_offset, R14_bcp);
+ }
+#if 0
+ assert(Rtmp != Rdst, "need separate temp register");
+ Register Rfirst = Rtmp;
+ lbz(Rfirst, bcp_offset, R14_bcp); // first byte
+ lbz(Rdst, bcp_offset+1, R14_bcp); // second byte
+
+ // Rdst = ((Rfirst<<8) & 0xFF00) | (Rdst &~ 0xFF00)
+ rldimi(/*RA=*/Rdst, /*RS=*/Rfirst, /*sh=*/8, /*mb=*/48);
+ if (is_signed == Signed) {
+ extsh(Rdst, Rdst);
+ }
+#endif
+}
+
+void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset,
+ Register Rdst,
+ signedOrNot is_signed) {
+ // Read Java big endian format.
+ if (bcp_offset & 3) { // Offset unaligned?
+ load_const_optimized(Rdst, bcp_offset);
+ if (is_signed == Signed) {
+ lwax(Rdst, R14_bcp, Rdst);
+ } else {
+ lwzx(Rdst, R14_bcp, Rdst);
+ }
+ } else {
+ if (is_signed == Signed) {
+ lwa(Rdst, bcp_offset, R14_bcp);
+ } else {
+ lwz(Rdst, bcp_offset, R14_bcp);
+ }
+ }
+}
+
+// Load the constant pool cache index from the bytecode stream.
+//
+// Kills / writes:
+// - Rdst, Rscratch
+void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size) {
+ assert(bcp_offset > 0, "bcp is still pointing to start of bytecode");
+ if (index_size == sizeof(u2)) {
+ get_2_byte_integer_at_bcp(bcp_offset, Rdst, Unsigned);
+ } else if (index_size == sizeof(u4)) {
+ assert(EnableInvokeDynamic, "giant index used only for JSR 292");
+ get_4_byte_integer_at_bcp(bcp_offset, Rdst, Signed);
+ assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line");
+ nand(Rdst, Rdst, Rdst); // convert to plain index
+ } else if (index_size == sizeof(u1)) {
+ lbz(Rdst, bcp_offset, R14_bcp);
+ } else {
+ ShouldNotReachHere();
+ }
+ // Rdst now contains cp cache index.
+}
+
+void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size) {
+ get_cache_index_at_bcp(cache, bcp_offset, index_size);
+ sldi(cache, cache, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord));
+ add(cache, R27_constPoolCache, cache);
+}
+
+// Load object from cpool->resolved_references(index).
+void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) {
+ assert_different_registers(result, index);
+ get_constant_pool(result);
+
+ // Convert from field index to resolved_references() index and from
+ // word index to byte offset. Since this is a java object, it can be compressed.
+ Register tmp = index; // reuse
+ sldi(tmp, index, LogBytesPerHeapOop);
+ // Load pointer for resolved_references[] objArray.
+ ld(result, ConstantPool::resolved_references_offset_in_bytes(), result);
+ // JNIHandles::resolve(result)
+ ld(result, 0, result);
+#ifdef ASSERT
+ Label index_ok;
+ lwa(R0, arrayOopDesc::length_offset_in_bytes(), result);
+ sldi(R0, R0, LogBytesPerHeapOop);
+ cmpd(CCR0, tmp, R0);
+ blt(CCR0, index_ok);
+ stop("resolved reference index out of bounds", 0x09256);
+ bind(index_ok);
+#endif
+ // Add in the index.
+ add(result, tmp, result);
+ load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result);
+}
+
+// Generate a subtype check: branch to ok_is_subtype if sub_klass is
+// a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2.
+void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1,
+ Register Rtmp2, Register Rtmp3, Label &ok_is_subtype) {
+ // Profile the not-null value's klass.
+ profile_typecheck(Rsub_klass, Rtmp1, Rtmp2);
+ check_klass_subtype(Rsub_klass, Rsuper_klass, Rtmp1, Rtmp2, ok_is_subtype);
+ profile_typecheck_failed(Rtmp1, Rtmp2);
+}
+
+void InterpreterMacroAssembler::generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1) {
+ Label done;
+ sub(Rmem_frame_size, R1_SP, Rmem_frame_size);
+ ld(Rscratch1, thread_(stack_overflow_limit));
+ cmpld(CCR0/*is_stack_overflow*/, Rmem_frame_size, Rscratch1);
+ bgt(CCR0/*is_stack_overflow*/, done);
+
+ // Load target address of the runtime stub.
+ assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order");
+ load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0);
+ mtctr(Rscratch1);
+ // Restore caller_sp.
+#ifdef ASSERT
+ ld(Rscratch1, 0, R1_SP);
+ ld(R0, 0, R21_sender_SP);
+ cmpd(CCR0, R0, Rscratch1);
+ asm_assert_eq("backlink", 0x547);
+#endif // ASSERT
+ mr(R1_SP, R21_sender_SP);
+ bctr();
+
+ align(32, 12);
+ bind(done);
+}
+
+// Separate these two to allow for delay slot in middle.
+// These are used to do a test and full jump to exception-throwing code.
+
+// Check that index is in range for array, then shift index by index_shift,
+// and put arrayOop + shifted_index into res.
+// Note: res is still shy of address by array offset into object.
+
+void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Register Rindex, int index_shift, Register Rtmp, Register Rres) {
+ // Check that index is in range for array, then shift index by index_shift,
+ // and put arrayOop + shifted_index into res.
+ // Note: res is still shy of address by array offset into object.
+ // Kills:
+ // - Rindex
+ // Writes:
+ // - Rres: Address that corresponds to the array index if check was successful.
+ verify_oop(Rarray);
+ const Register Rlength = R0;
+ const Register RsxtIndex = Rtmp;
+ Label LisNull, LnotOOR;
+
+ // Array nullcheck
+ if (!ImplicitNullChecks) {
+ cmpdi(CCR0, Rarray, 0);
+ beq(CCR0, LisNull);
+ } else {
+ null_check_throw(Rarray, arrayOopDesc::length_offset_in_bytes(), /*temp*/RsxtIndex);
+ }
+
+ // Rindex might contain garbage in upper bits (remember that we don't sign extend
+ // during integer arithmetic operations). So kill them and put value into same register
+ // where ArrayIndexOutOfBounds would expect the index in.
+ rldicl(RsxtIndex, Rindex, 0, 32); // zero extend 32 bit -> 64 bit
+
+ // Index check
+ lwz(Rlength, arrayOopDesc::length_offset_in_bytes(), Rarray);
+ cmplw(CCR0, Rindex, Rlength);
+ sldi(RsxtIndex, RsxtIndex, index_shift);
+ blt(CCR0, LnotOOR);
+ load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
+ mtctr(Rtmp);
+ bctr();
+
+ if (!ImplicitNullChecks) {
+ bind(LisNull);
+ load_dispatch_table(Rtmp, (address*)Interpreter::_throw_NullPointerException_entry);
+ mtctr(Rtmp);
+ bctr();
+ }
+
+ align(32, 16);
+ bind(LnotOOR);
+
+ // Calc address
+ add(Rres, RsxtIndex, Rarray);
+}
+
+void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) {
+ // pop array
+ pop_ptr(array);
+
+ // check array
+ index_check_without_pop(array, index, index_shift, tmp, res);
+}
+
+void InterpreterMacroAssembler::get_const(Register Rdst) {
+ ld(Rdst, in_bytes(Method::const_offset()), R19_method);
+}
+
+void InterpreterMacroAssembler::get_constant_pool(Register Rdst) {
+ get_const(Rdst);
+ ld(Rdst, in_bytes(ConstMethod::constants_offset()), Rdst);
+}
+
+void InterpreterMacroAssembler::get_constant_pool_cache(Register Rdst) {
+ get_constant_pool(Rdst);
+ ld(Rdst, ConstantPool::cache_offset_in_bytes(), Rdst);
+}
+
+void InterpreterMacroAssembler::get_cpool_and_tags(Register Rcpool, Register Rtags) {
+ get_constant_pool(Rcpool);
+ ld(Rtags, ConstantPool::tags_offset_in_bytes(), Rcpool);
+}
+
+// Unlock if synchronized method.
+//
+// Unlock the receiver if this is a synchronized method.
+// Unlock any Java monitors from synchronized blocks.
+//
+// If there are locked Java monitors
+// If throw_monitor_exception
+// throws IllegalMonitorStateException
+// Else if install_monitor_exception
+// installs IllegalMonitorStateException
+// Else
+// no error processing
+void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state,
+ bool throw_monitor_exception,
+ bool install_monitor_exception) {
+ Label Lunlocked, Lno_unlock;
+ {
+ Register Rdo_not_unlock_flag = R11_scratch1;
+ Register Raccess_flags = R12_scratch2;
+
+ // Check if synchronized method or unlocking prevented by
+ // JavaThread::do_not_unlock_if_synchronized flag.
+ lbz(Rdo_not_unlock_flag, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ lwz(Raccess_flags, in_bytes(Method::access_flags_offset()), R19_method);
+ li(R0, 0);
+ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread); // reset flag
+
+ push(state);
+
+ // Skip if we don't have to unlock.
+ rldicl_(R0, Raccess_flags, 64-JVM_ACC_SYNCHRONIZED_BIT, 63); // Extract bit and compare to 0.
+ beq(CCR0, Lunlocked);
+
+ cmpwi(CCR0, Rdo_not_unlock_flag, 0);
+ bne(CCR0, Lno_unlock);
+ }
+
+ // Unlock
+ {
+ Register Rmonitor_base = R11_scratch1;
+
+ Label Lunlock;
+ // If it's still locked, everything is ok, unlock it.
+ ld(Rmonitor_base, 0, R1_SP);
+ addi(Rmonitor_base, Rmonitor_base, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base
+
+ ld(R0, BasicObjectLock::obj_offset_in_bytes(), Rmonitor_base);
+ cmpdi(CCR0, R0, 0);
+ bne(CCR0, Lunlock);
+
+ // If it's already unlocked, throw exception.
+ if (throw_monitor_exception) {
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+ should_not_reach_here();
+ } else {
+ if (install_monitor_exception) {
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
+ b(Lunlocked);
+ }
+ }
+
+ bind(Lunlock);
+ unlock_object(Rmonitor_base);
+ }
+
+ // Check that all other monitors are unlocked. Throw IllegelMonitorState exception if not.
+ bind(Lunlocked);
+ {
+ Label Lexception, Lrestart;
+ Register Rcurrent_obj_addr = R11_scratch1;
+ const int delta = frame::interpreter_frame_monitor_size_in_bytes();
+ assert((delta & LongAlignmentMask) == 0, "sizeof BasicObjectLock must be even number of doublewords");
+
+ bind(Lrestart);
+ // Set up search loop: Calc num of iterations.
+ {
+ Register Riterations = R12_scratch2;
+ Register Rmonitor_base = Rcurrent_obj_addr;
+ ld(Rmonitor_base, 0, R1_SP);
+ addi(Rmonitor_base, Rmonitor_base, - frame::ijava_state_size); // Monitor base
+
+ subf_(Riterations, R26_monitor, Rmonitor_base);
+ ble(CCR0, Lno_unlock);
+
+ addi(Rcurrent_obj_addr, Rmonitor_base, BasicObjectLock::obj_offset_in_bytes() - frame::interpreter_frame_monitor_size_in_bytes());
+ // Check if any monitor is on stack, bail out if not
+ srdi(Riterations, Riterations, exact_log2(delta));
+ mtctr(Riterations);
+ }
+
+ // The search loop: Look for locked monitors.
+ {
+ const Register Rcurrent_obj = R0;
+ Label Lloop;
+
+ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta);
+ bind(Lloop);
+
+ // Check if current entry is used.
+ cmpdi(CCR0, Rcurrent_obj, 0);
+ bne(CCR0, Lexception);
+ // Preload next iteration's compare value.
+ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, -delta);
+ bdnz(Lloop);
+ }
+ // Fell through: Everything's unlocked => finish.
+ b(Lno_unlock);
+
+ // An object is still locked => need to throw exception.
+ bind(Lexception);
+ if (throw_monitor_exception) {
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+ should_not_reach_here();
+ } else {
+ // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception.
+ // Unlock does not block, so don't have to worry about the frame.
+ Register Rmonitor_addr = R11_scratch1;
+ addi(Rmonitor_addr, Rcurrent_obj_addr, -BasicObjectLock::obj_offset_in_bytes() + delta);
+ unlock_object(Rmonitor_addr);
+ if (install_monitor_exception) {
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception));
+ }
+ b(Lrestart);
+ }
+ }
+
+ align(32, 12);
+ bind(Lno_unlock);
+ pop(state);
+}
+
+// Support function for remove_activation & Co.
+void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, Register Rscratch1, Register Rscratch2) {
+ // Pop interpreter frame.
+ ld(Rscratch1, 0, R1_SP); // *SP
+ ld(Rsender_sp, _ijava_state_neg(sender_sp), Rscratch1); // top_frame_sp
+ ld(Rscratch2, 0, Rscratch1); // **SP
+#ifdef ASSERT
+ {
+ Label Lok;
+ ld(R0, _ijava_state_neg(ijava_reserved), Rscratch1);
+ cmpdi(CCR0, R0, 0x5afe);
+ beq(CCR0, Lok);
+ stop("frame corrupted (remove activation)", 0x5afe);
+ bind(Lok);
+ }
+#endif
+ if (return_pc!=noreg) {
+ ld(return_pc, _abi(lr), Rscratch1); // LR
+ }
+
+ // Merge top frames.
+ subf(Rscratch1, R1_SP, Rsender_sp); // top_frame_sp - SP
+ stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP
+}
+
+// Remove activation.
+//
+// Unlock the receiver if this is a synchronized method.
+// Unlock any Java monitors from synchronized blocks.
+// Remove the activation from the stack.
+//
+// If there are locked Java monitors
+// If throw_monitor_exception
+// throws IllegalMonitorStateException
+// Else if install_monitor_exception
+// installs IllegalMonitorStateException
+// Else
+// no error processing
+void InterpreterMacroAssembler::remove_activation(TosState state,
+ bool throw_monitor_exception,
+ bool install_monitor_exception) {
+ unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
+
+ // Save result (push state before jvmti call and pop it afterwards) and notify jvmti.
+ notify_method_exit(false, state, NotifyJVMTI, true);
+
+ verify_oop(R17_tos, state);
+ verify_thread();
+
+ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
+ mtlr(R0);
+}
+
+#endif // !CC_INTERP
+
// Lock object
//
// Registers alive
@@ -81,7 +767,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
assert_different_registers(displaced_header, object_mark_addr, current_header, tmp);
-
// markOop displaced_header = obj->mark().set_unlocked();
// Load markOop from object into displaced_header.
@@ -94,7 +779,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
// Set displaced_header to be (markOop of object | UNLOCK_VALUE).
ori(displaced_header, displaced_header, markOopDesc::unlocked_value);
-
// monitor->lock()->set_displaced_header(displaced_header);
// Initialize the box (Must happen before we update the object mark!).
@@ -147,7 +831,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
BasicLock::displaced_header_offset_in_bytes(), monitor);
b(done);
-
// } else {
// // Slow path.
// InterpreterRuntime::monitorenter(THREAD, monitor);
@@ -158,7 +841,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter),
monitor, /*check_for_exceptions=*/true CC_INTERP_ONLY(&& false));
// }
-
+ align(32, 12);
bind(done);
}
}
@@ -173,13 +856,13 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) {
void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_exceptions) {
if (UseHeavyMonitors) {
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit),
- monitor, /*check_for_exceptions=*/false);
+ monitor, check_for_exceptions CC_INTERP_ONLY(&& false));
} else {
// template code:
//
// if ((displaced_header = monitor->displaced_header()) == NULL) {
- // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL.
+ // // Recursive unlock. Mark the monitor unlocked by setting the object field to NULL.
// monitor->set_obj(NULL);
// } else if (Atomic::cmpxchg_ptr(displaced_header, obj->mark_addr(), monitor) == monitor) {
// // We swapped the unlocked mark in displaced_header into the object's mark word.
@@ -221,7 +904,7 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e
// If we still have a lightweight lock, unlock the object and be done.
// The object address from the monitor is in object.
- if (!UseBiasedLocking) ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor);
+ if (!UseBiasedLocking) { ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor); }
addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes());
// We have the displaced header in displaced_header. If the lock is still
@@ -261,6 +944,959 @@ void InterpreterMacroAssembler::unlock_object(Register monitor, bool check_for_e
}
}
+#ifndef CC_INTERP
+
+// Load compiled (i2c) or interpreter entry when calling from interpreted and
+// do the call. Centralized so that all interpreter calls will do the same actions.
+// If jvmti single stepping is on for a thread we must not call compiled code.
+//
+// Input:
+// - Rtarget_method: method to call
+// - Rret_addr: return address
+// - 2 scratch regs
+//
+void InterpreterMacroAssembler::call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2) {
+ assert_different_registers(Rscratch1, Rscratch2, Rtarget_method, Rret_addr);
+ // Assume we want to go compiled if available.
+ const Register Rtarget_addr = Rscratch1;
+ const Register Rinterp_only = Rscratch2;
+
+ ld(Rtarget_addr, in_bytes(Method::from_interpreted_offset()), Rtarget_method);
+
+ if (JvmtiExport::can_post_interpreter_events()) {
+ lwz(Rinterp_only, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread);
+
+ // JVMTI events, such as single-stepping, are implemented partly by avoiding running
+ // compiled code in threads for which the event is enabled. Check here for
+ // interp_only_mode if these events CAN be enabled.
+ Label done;
+ verify_thread();
+ cmpwi(CCR0, Rinterp_only, 0);
+ beq(CCR0, done);
+ ld(Rtarget_addr, in_bytes(Method::interpreter_entry_offset()), Rtarget_method);
+ align(32, 12);
+ bind(done);
+ }
+
+#ifdef ASSERT
+ {
+ Label Lok;
+ cmpdi(CCR0, Rtarget_addr, 0);
+ bne(CCR0, Lok);
+ stop("null entry point");
+ bind(Lok);
+ }
+#endif // ASSERT
+
+ mr(R21_sender_SP, R1_SP);
+
+ // Calc a precise SP for the call. The SP value we calculated in
+ // generate_fixed_frame() is based on the max_stack() value, so we would waste stack space
+ // if esp is not max. Also, the i2c adapter extends the stack space without restoring
+ // our pre-calced value, so repeating calls via i2c would result in stack overflow.
+ // Since esp already points to an empty slot, we just have to sub 1 additional slot
+ // to meet the abi scratch requirements.
+ // The max_stack pointer will get restored by means of the GR_Lmax_stack local in
+ // the return entry of the interpreter.
+ addi(Rscratch2, R15_esp, Interpreter::stackElementSize - frame::abi_reg_args_size);
+ clrrdi(Rscratch2, Rscratch2, exact_log2(frame::alignment_in_bytes)); // round towards smaller address
+ resize_frame_absolute(Rscratch2, Rscratch2, R0);
+
+ mr_if_needed(R19_method, Rtarget_method);
+ mtctr(Rtarget_addr);
+ mtlr(Rret_addr);
+
+ save_interpreter_state(Rscratch2);
+#ifdef ASSERT
+ ld(Rscratch1, _ijava_state_neg(top_frame_sp), Rscratch2); // Rscratch2 contains fp
+ cmpd(CCR0, R21_sender_SP, Rscratch1);
+ asm_assert_eq("top_frame_sp incorrect", 0x951);
+#endif
+
+ bctr();
+}
+
+// Set the method data pointer for the current bcp.
+void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+ Label get_continue;
+ ld(R28_mdx, in_bytes(Method::method_data_offset()), R19_method);
+ test_method_data_pointer(get_continue);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), R19_method, R14_bcp);
+
+ addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset()));
+ add(R28_mdx, R28_mdx, R3_RET);
+ bind(get_continue);
+}
+
+// Test ImethodDataPtr. If it is null, continue at the specified label.
+void InterpreterMacroAssembler::test_method_data_pointer(Label& zero_continue) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+ cmpdi(CCR0, R28_mdx, 0);
+ beq(CCR0, zero_continue);
+}
+
+void InterpreterMacroAssembler::verify_method_data_pointer() {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+#ifdef ASSERT
+ Label verify_continue;
+ test_method_data_pointer(verify_continue);
+
+ // If the mdp is valid, it will point to a DataLayout header which is
+ // consistent with the bcp. The converse is highly probable also.
+ lhz(R11_scratch1, in_bytes(DataLayout::bci_offset()), R28_mdx);
+ ld(R12_scratch2, in_bytes(Method::const_offset()), R19_method);
+ addi(R11_scratch1, R11_scratch1, in_bytes(ConstMethod::codes_offset()));
+ add(R11_scratch1, R12_scratch2, R12_scratch2);
+ cmpd(CCR0, R11_scratch1, R14_bcp);
+ beq(CCR0, verify_continue);
+
+ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp ), R19_method, R14_bcp, R28_mdx);
+
+ bind(verify_continue);
+#endif
+}
+
+void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count,
+ Register Rscratch,
+ Label &profile_continue) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+ // Control will flow to "profile_continue" if the counter is less than the
+ // limit or if we call profile_method().
+ Label done;
+
+ // If no method data exists, and the counter is high enough, make one.
+ int ipl_offs = load_const_optimized(Rscratch, &InvocationCounter::InterpreterProfileLimit, R0, true);
+ lwz(Rscratch, ipl_offs, Rscratch);
+
+ cmpdi(CCR0, R28_mdx, 0);
+ // Test to see if we should create a method data oop.
+ cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count);
+ bne(CCR0, done);
+ bge(CCR1, profile_continue);
+
+ // Build it now.
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ set_method_data_pointer_for_bcp();
+ b(profile_continue);
+
+ align(32, 12);
+ bind(done);
+}
+
+void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp) {
+ assert_different_registers(backedge_count, Rtmp, branch_bcp);
+ assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr");
+
+ Label did_not_overflow;
+ Label overflow_with_error;
+
+ int ibbl_offs = load_const_optimized(Rtmp, &InvocationCounter::InterpreterBackwardBranchLimit, R0, true);
+ lwz(Rtmp, ibbl_offs, Rtmp);
+ cmpw(CCR0, backedge_count, Rtmp);
+
+ blt(CCR0, did_not_overflow);
+
+ // When ProfileInterpreter is on, the backedge_count comes from the
+ // methodDataOop, which value does not get reset on the call to
+ // frequency_counter_overflow(). To avoid excessive calls to the overflow
+ // routine while the method is being compiled, add a second test to make sure
+ // the overflow function is called only once every overflow_frequency.
+ if (ProfileInterpreter) {
+ const int overflow_frequency = 1024;
+ li(Rtmp, overflow_frequency-1);
+ andr(Rtmp, Rtmp, backedge_count);
+ cmpwi(CCR0, Rtmp, 0);
+ bne(CCR0, did_not_overflow);
+ }
+
+ // Overflow in loop, pass branch bytecode.
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, true);
+
+ // Was an OSR adapter generated?
+ // O0 = osr nmethod
+ cmpdi(CCR0, R3_RET, 0);
+ beq(CCR0, overflow_with_error);
+
+ // Has the nmethod been invalidated already?
+ lwz(Rtmp, nmethod::entry_bci_offset(), R3_RET);
+ cmpwi(CCR0, Rtmp, InvalidOSREntryBci);
+ beq(CCR0, overflow_with_error);
+
+ // Migrate the interpreter frame off of the stack.
+ // We can use all registers because we will not return to interpreter from this point.
+
+ // Save nmethod.
+ const Register osr_nmethod = R31;
+ mr(osr_nmethod, R3_RET);
+ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread);
+ reset_last_Java_frame();
+ // OSR buffer is in ARG1
+
+ // Remove the interpreter frame.
+ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
+
+ // Jump to the osr code.
+ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod);
+ mtlr(R0);
+ mtctr(R11_scratch1);
+ bctr();
+
+ align(32, 12);
+ bind(overflow_with_error);
+ bind(did_not_overflow);
+}
+
+// Store a value at some constant offset from the method data pointer.
+void InterpreterMacroAssembler::set_mdp_data_at(int constant, Register value) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ std(value, constant, R28_mdx);
+}
+
+// Increment the value at some constant offset from the method data pointer.
+void InterpreterMacroAssembler::increment_mdp_data_at(int constant,
+ Register counter_addr,
+ Register Rbumped_count,
+ bool decrement) {
+ // Locate the counter at a fixed offset from the mdp:
+ addi(counter_addr, R28_mdx, constant);
+ increment_mdp_data_at(counter_addr, Rbumped_count, decrement);
+}
+
+// Increment the value at some non-fixed (reg + constant) offset from
+// the method data pointer.
+void InterpreterMacroAssembler::increment_mdp_data_at(Register reg,
+ int constant,
+ Register scratch,
+ Register Rbumped_count,
+ bool decrement) {
+ // Add the constant to reg to get the offset.
+ add(scratch, R28_mdx, reg);
+ // Then calculate the counter address.
+ addi(scratch, scratch, constant);
+ increment_mdp_data_at(scratch, Rbumped_count, decrement);
+}
+
+void InterpreterMacroAssembler::increment_mdp_data_at(Register counter_addr,
+ Register Rbumped_count,
+ bool decrement) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ // Load the counter.
+ ld(Rbumped_count, 0, counter_addr);
+
+ if (decrement) {
+ // Decrement the register. Set condition codes.
+ addi(Rbumped_count, Rbumped_count, - DataLayout::counter_increment);
+ // Store the decremented counter, if it is still negative.
+ std(Rbumped_count, 0, counter_addr);
+ // Note: add/sub overflow check are not ported, since 64 bit
+ // calculation should never overflow.
+ } else {
+ // Increment the register. Set carry flag.
+ addi(Rbumped_count, Rbumped_count, DataLayout::counter_increment);
+ // Store the incremented counter.
+ std(Rbumped_count, 0, counter_addr);
+ }
+}
+
+// Set a flag value at the current method data pointer position.
+void InterpreterMacroAssembler::set_mdp_flag_at(int flag_constant,
+ Register scratch) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+ // Load the data header.
+ lbz(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx);
+ // Set the flag.
+ ori(scratch, scratch, flag_constant);
+ // Store the modified header.
+ stb(scratch, in_bytes(DataLayout::flags_offset()), R28_mdx);
+}
+
+// Test the location at some offset from the method data pointer.
+// If it is not equal to value, branch to the not_equal_continue Label.
+void InterpreterMacroAssembler::test_mdp_data_at(int offset,
+ Register value,
+ Label& not_equal_continue,
+ Register test_out) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ ld(test_out, offset, R28_mdx);
+ cmpd(CCR0, value, test_out);
+ bne(CCR0, not_equal_continue);
+}
+
+// Update the method data pointer by the displacement located at some fixed
+// offset from the method data pointer.
+void InterpreterMacroAssembler::update_mdp_by_offset(int offset_of_disp,
+ Register scratch) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ ld(scratch, offset_of_disp, R28_mdx);
+ add(R28_mdx, scratch, R28_mdx);
+}
+
+// Update the method data pointer by the displacement located at the
+// offset (reg + offset_of_disp).
+void InterpreterMacroAssembler::update_mdp_by_offset(Register reg,
+ int offset_of_disp,
+ Register scratch) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ add(scratch, reg, R28_mdx);
+ ld(scratch, offset_of_disp, scratch);
+ add(R28_mdx, scratch, R28_mdx);
+}
+
+// Update the method data pointer by a simple constant displacement.
+void InterpreterMacroAssembler::update_mdp_by_constant(int constant) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+ addi(R28_mdx, R28_mdx, constant);
+}
+
+// Update the method data pointer for a _ret bytecode whose target
+// was not among our cached targets.
+void InterpreterMacroAssembler::update_mdp_for_ret(TosState state,
+ Register return_bci) {
+ assert(ProfileInterpreter, "must be profiling interpreter");
+
+ push(state);
+ assert(return_bci->is_nonvolatile(), "need to protect return_bci");
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci);
+ pop(state);
+}
+
+// Increments the backedge counter.
+// Returns backedge counter + invocation counter in Rdst.
+void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcounters, const Register Rdst,
+ const Register Rtmp1, Register Rscratch) {
+ assert(UseCompiler, "incrementing must be useful");
+ assert_different_registers(Rdst, Rtmp1);
+ const Register invocation_counter = Rtmp1;
+ const Register counter = Rdst;
+ // TODO ppc port assert(4 == InvocationCounter::sz_counter(), "unexpected field size.");
+
+ // Load backedge counter.
+ lwz(counter, in_bytes(MethodCounters::backedge_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()), Rcounters);
+ // Load invocation counter.
+ lwz(invocation_counter, in_bytes(MethodCounters::invocation_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()), Rcounters);
+
+ // Add the delta to the backedge counter.
+ addi(counter, counter, InvocationCounter::count_increment);
+
+ // Mask the invocation counter.
+ li(Rscratch, InvocationCounter::count_mask_value);
+ andr(invocation_counter, invocation_counter, Rscratch);
+
+ // Store new counter value.
+ stw(counter, in_bytes(MethodCounters::backedge_counter_offset()) +
+ in_bytes(InvocationCounter::counter_offset()), Rcounters);
+ // Return invocation counter + backedge counter.
+ add(counter, counter, invocation_counter);
+}
+
+// Count a taken branch in the bytecodes.
+void InterpreterMacroAssembler::profile_taken_branch(Register scratch, Register bumped_count) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // We are taking a branch. Increment the taken count.
+ increment_mdp_data_at(in_bytes(JumpData::taken_offset()), scratch, bumped_count);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_offset(in_bytes(JumpData::displacement_offset()), scratch);
+ bind (profile_continue);
+ }
+}
+
+// Count a not-taken branch in the bytecodes.
+void InterpreterMacroAssembler::profile_not_taken_branch(Register scratch1, Register scratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // We are taking a branch. Increment the not taken count.
+ increment_mdp_data_at(in_bytes(BranchData::not_taken_offset()), scratch1, scratch2);
+
+ // The method data pointer needs to be updated to correspond to the
+ // next bytecode.
+ update_mdp_by_constant(in_bytes(BranchData::branch_data_size()));
+ bind (profile_continue);
+ }
+}
+
+// Count a non-virtual call in the bytecodes.
+void InterpreterMacroAssembler::profile_call(Register scratch1, Register scratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // We are making a call. Increment the count.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_constant(in_bytes(CounterData::counter_data_size()));
+ bind (profile_continue);
+ }
+}
+
+// Count a final call in the bytecodes.
+void InterpreterMacroAssembler::profile_final_call(Register scratch1, Register scratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // We are making a call. Increment the count.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
+ bind (profile_continue);
+ }
+}
+
+// Count a virtual call in the bytecodes.
+void InterpreterMacroAssembler::profile_virtual_call(Register Rreceiver,
+ Register Rscratch1,
+ Register Rscratch2,
+ bool receiver_can_be_null) {
+ if (!ProfileInterpreter) { return; }
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ Label skip_receiver_profile;
+ if (receiver_can_be_null) {
+ Label not_null;
+ cmpdi(CCR0, Rreceiver, 0);
+ bne(CCR0, not_null);
+ // We are making a call. Increment the count for null receiver.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), Rscratch1, Rscratch2);
+ b(skip_receiver_profile);
+ bind(not_null);
+ }
+
+ // Record the receiver type.
+ record_klass_in_profile(Rreceiver, Rscratch1, Rscratch2, true);
+ bind(skip_receiver_profile);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
+ bind (profile_continue);
+}
+
+void InterpreterMacroAssembler::profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ int mdp_delta = in_bytes(BitData::bit_data_size());
+ if (TypeProfileCasts) {
+ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+
+ // Record the object type.
+ record_klass_in_profile(Rklass, Rscratch1, Rscratch2, false);
+ }
+
+ // The method data pointer needs to be updated.
+ update_mdp_by_constant(mdp_delta);
+
+ bind (profile_continue);
+ }
+}
+
+void InterpreterMacroAssembler::profile_typecheck_failed(Register Rscratch1, Register Rscratch2) {
+ if (ProfileInterpreter && TypeProfileCasts) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ int count_offset = in_bytes(CounterData::count_offset());
+ // Back up the address, since we have already bumped the mdp.
+ count_offset -= in_bytes(VirtualCallData::virtual_call_data_size());
+
+ // *Decrement* the counter. We expect to see zero or small negatives.
+ increment_mdp_data_at(count_offset, Rscratch1, Rscratch2, true);
+
+ bind (profile_continue);
+ }
+}
+
+// Count a ret in the bytecodes.
+void InterpreterMacroAssembler::profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+ uint row;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // Update the total ret count.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2 );
+
+ for (row = 0; row < RetData::row_limit(); row++) {
+ Label next_test;
+
+ // See if return_bci is equal to bci[n]:
+ test_mdp_data_at(in_bytes(RetData::bci_offset(row)), return_bci, next_test, scratch1);
+
+ // return_bci is equal to bci[n]. Increment the count.
+ increment_mdp_data_at(in_bytes(RetData::bci_count_offset(row)), scratch1, scratch2);
+
+ // The method data pointer needs to be updated to reflect the new target.
+ update_mdp_by_offset(in_bytes(RetData::bci_displacement_offset(row)), scratch1);
+ b(profile_continue);
+ bind(next_test);
+ }
+
+ update_mdp_for_ret(state, return_bci);
+
+ bind (profile_continue);
+ }
+}
+
+// Count the default case of a switch construct.
+void InterpreterMacroAssembler::profile_switch_default(Register scratch1, Register scratch2) {
+ if (ProfileInterpreter) {
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // Update the default case count
+ increment_mdp_data_at(in_bytes(MultiBranchData::default_count_offset()),
+ scratch1, scratch2);
+
+ // The method data pointer needs to be updated.
+ update_mdp_by_offset(in_bytes(MultiBranchData::default_displacement_offset()),
+ scratch1);
+
+ bind (profile_continue);
+ }
+}
+
+// Count the index'th case of a switch construct.
+void InterpreterMacroAssembler::profile_switch_case(Register index,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3) {
+ if (ProfileInterpreter) {
+ assert_different_registers(index, scratch1, scratch2, scratch3);
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes().
+ li(scratch3, in_bytes(MultiBranchData::case_array_offset()));
+
+ assert (in_bytes(MultiBranchData::per_case_size()) == 16, "so that shladd works");
+ sldi(scratch1, index, exact_log2(in_bytes(MultiBranchData::per_case_size())));
+ add(scratch1, scratch1, scratch3);
+
+ // Update the case count.
+ increment_mdp_data_at(scratch1, in_bytes(MultiBranchData::relative_count_offset()), scratch2, scratch3);
+
+ // The method data pointer needs to be updated.
+ update_mdp_by_offset(scratch1, in_bytes(MultiBranchData::relative_displacement_offset()), scratch2);
+
+ bind (profile_continue);
+ }
+}
+
+void InterpreterMacroAssembler::profile_null_seen(Register Rscratch1, Register Rscratch2) {
+ if (ProfileInterpreter) {
+ assert_different_registers(Rscratch1, Rscratch2);
+ Label profile_continue;
+
+ // If no method data exists, go to profile_continue.
+ test_method_data_pointer(profile_continue);
+
+ set_mdp_flag_at(BitData::null_seen_byte_constant(), Rscratch1);
+
+ // The method data pointer needs to be updated.
+ int mdp_delta = in_bytes(BitData::bit_data_size());
+ if (TypeProfileCasts) {
+ mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
+ }
+ update_mdp_by_constant(mdp_delta);
+
+ bind (profile_continue);
+ }
+}
+
+void InterpreterMacroAssembler::record_klass_in_profile(Register Rreceiver,
+ Register Rscratch1, Register Rscratch2,
+ bool is_virtual_call) {
+ assert(ProfileInterpreter, "must be profiling");
+ assert_different_registers(Rreceiver, Rscratch1, Rscratch2);
+
+ Label done;
+ record_klass_in_profile_helper(Rreceiver, Rscratch1, Rscratch2, 0, done, is_virtual_call);
+ bind (done);
+}
+
+void InterpreterMacroAssembler::record_klass_in_profile_helper(
+ Register receiver, Register scratch1, Register scratch2,
+ int start_row, Label& done, bool is_virtual_call) {
+ if (TypeProfileWidth == 0) {
+ if (is_virtual_call) {
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2);
+ }
+ return;
+ }
+
+ int last_row = VirtualCallData::row_limit() - 1;
+ assert(start_row <= last_row, "must be work left to do");
+ // Test this row for both the receiver and for null.
+ // Take any of three different outcomes:
+ // 1. found receiver => increment count and goto done
+ // 2. found null => keep looking for case 1, maybe allocate this cell
+ // 3. found something else => keep looking for cases 1 and 2
+ // Case 3 is handled by a recursive call.
+ for (int row = start_row; row <= last_row; row++) {
+ Label next_test;
+ bool test_for_null_also = (row == start_row);
+
+ // See if the receiver is receiver[n].
+ int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
+ test_mdp_data_at(recvr_offset, receiver, next_test, scratch1);
+ // delayed()->tst(scratch);
+
+ // The receiver is receiver[n]. Increment count[n].
+ int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
+ increment_mdp_data_at(count_offset, scratch1, scratch2);
+ b(done);
+ bind(next_test);
+
+ if (test_for_null_also) {
+ Label found_null;
+ // Failed the equality check on receiver[n]... Test for null.
+ if (start_row == last_row) {
+ // The only thing left to do is handle the null case.
+ if (is_virtual_call) {
+ // Scratch1 contains test_out from test_mdp_data_at.
+ cmpdi(CCR0, scratch1, 0);
+ beq(CCR0, found_null);
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polymorphic case.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch1, scratch2);
+ b(done);
+ bind(found_null);
+ } else {
+ cmpdi(CCR0, scratch1, 0);
+ bne(CCR0, done);
+ }
+ break;
+ }
+ // Since null is rare, make it be the branch-taken case.
+ cmpdi(CCR0, scratch1, 0);
+ beq(CCR0, found_null);
+
+ // Put all the "Case 3" tests here.
+ record_klass_in_profile_helper(receiver, scratch1, scratch2, start_row + 1, done, is_virtual_call);
+
+ // Found a null. Keep searching for a matching receiver,
+ // but remember that this is an empty (unused) slot.
+ bind(found_null);
+ }
+ }
+
+ // In the fall-through case, we found no matching receiver, but we
+ // observed the receiver[start_row] is NULL.
+
+ // Fill in the receiver field and increment the count.
+ int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row));
+ set_mdp_data_at(recvr_offset, receiver);
+ int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
+ li(scratch1, DataLayout::counter_increment);
+ set_mdp_data_at(count_offset, scratch1);
+ if (start_row > 0) {
+ b(done);
+ }
+}
+
+// Add a InterpMonitorElem to stack (see frame_sparc.hpp).
+void InterpreterMacroAssembler::add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2) {
+
+ // Very-local scratch registers.
+ const Register esp = Rtemp1;
+ const Register slot = Rtemp2;
+
+ // Extracted monitor_size.
+ int monitor_size = frame::interpreter_frame_monitor_size_in_bytes();
+ assert(Assembler::is_aligned((unsigned int)monitor_size,
+ (unsigned int)frame::alignment_in_bytes),
+ "size of a monitor must respect alignment of SP");
+
+ resize_frame(-monitor_size, /*temp*/esp); // Allocate space for new monitor
+ std(R1_SP, _ijava_state_neg(top_frame_sp), esp); // esp contains fp
+
+ // Shuffle expression stack down. Recall that stack_base points
+ // just above the new expression stack bottom. Old_tos and new_tos
+ // are used to scan thru the old and new expression stacks.
+ if (!stack_is_empty) {
+ Label copy_slot, copy_slot_finished;
+ const Register n_slots = slot;
+
+ addi(esp, R15_esp, Interpreter::stackElementSize); // Point to first element (pre-pushed stack).
+ subf(n_slots, esp, R26_monitor);
+ srdi_(n_slots, n_slots, LogBytesPerWord); // Compute number of slots to copy.
+ assert(LogBytesPerWord == 3, "conflicts assembler instructions");
+ beq(CCR0, copy_slot_finished); // Nothing to copy.
+
+ mtctr(n_slots);
+
+ // loop
+ bind(copy_slot);
+ ld(slot, 0, esp); // Move expression stack down.
+ std(slot, -monitor_size, esp); // distance = monitor_size
+ addi(esp, esp, BytesPerWord);
+ bdnz(copy_slot);
+
+ bind(copy_slot_finished);
+ }
+
+ addi(R15_esp, R15_esp, -monitor_size);
+ addi(R26_monitor, R26_monitor, -monitor_size);
+
+ // Restart interpreter
+}
+
+// ============================================================================
+// Java locals access
+
+// Load a local variable at index in Rindex into register Rdst_value.
+// Also puts address of local into Rdst_address as a service.
+// Kills:
+// - Rdst_value
+// - Rdst_address
+void InterpreterMacroAssembler::load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex) {
+ sldi(Rdst_address, Rindex, Interpreter::logStackElementSize);
+ subf(Rdst_address, Rdst_address, R18_locals);
+ lwz(Rdst_value, 0, Rdst_address);
+}
+
+// Load a local variable at index in Rindex into register Rdst_value.
+// Also puts address of local into Rdst_address as a service.
+// Kills:
+// - Rdst_value
+// - Rdst_address
+void InterpreterMacroAssembler::load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex) {
+ sldi(Rdst_address, Rindex, Interpreter::logStackElementSize);
+ subf(Rdst_address, Rdst_address, R18_locals);
+ ld(Rdst_value, -8, Rdst_address);
+}
+
+// Load a local variable at index in Rindex into register Rdst_value.
+// Also puts address of local into Rdst_address as a service.
+// Input:
+// - Rindex: slot nr of local variable
+// Kills:
+// - Rdst_value
+// - Rdst_address
+void InterpreterMacroAssembler::load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex) {
+ sldi(Rdst_address, Rindex, Interpreter::logStackElementSize);
+ subf(Rdst_address, Rdst_address, R18_locals);
+ ld(Rdst_value, 0, Rdst_address);
+}
+
+// Load a local variable at index in Rindex into register Rdst_value.
+// Also puts address of local into Rdst_address as a service.
+// Kills:
+// - Rdst_value
+// - Rdst_address
+void InterpreterMacroAssembler::load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) {
+ sldi(Rdst_address, Rindex, Interpreter::logStackElementSize);
+ subf(Rdst_address, Rdst_address, R18_locals);
+ lfs(Rdst_value, 0, Rdst_address);
+}
+
+// Load a local variable at index in Rindex into register Rdst_value.
+// Also puts address of local into Rdst_address as a service.
+// Kills:
+// - Rdst_value
+// - Rdst_address
+void InterpreterMacroAssembler::load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex) {
+ sldi(Rdst_address, Rindex, Interpreter::logStackElementSize);
+ subf(Rdst_address, Rdst_address, R18_locals);
+ lfd(Rdst_value, -8, Rdst_address);
+}
+
+// Store an int value at local variable slot Rindex.
+// Kills:
+// - Rindex
+void InterpreterMacroAssembler::store_local_int(Register Rvalue, Register Rindex) {
+ sldi(Rindex, Rindex, Interpreter::logStackElementSize);
+ subf(Rindex, Rindex, R18_locals);
+ stw(Rvalue, 0, Rindex);
+}
+
+// Store a long value at local variable slot Rindex.
+// Kills:
+// - Rindex
+void InterpreterMacroAssembler::store_local_long(Register Rvalue, Register Rindex) {
+ sldi(Rindex, Rindex, Interpreter::logStackElementSize);
+ subf(Rindex, Rindex, R18_locals);
+ std(Rvalue, -8, Rindex);
+}
+
+// Store an oop value at local variable slot Rindex.
+// Kills:
+// - Rindex
+void InterpreterMacroAssembler::store_local_ptr(Register Rvalue, Register Rindex) {
+ sldi(Rindex, Rindex, Interpreter::logStackElementSize);
+ subf(Rindex, Rindex, R18_locals);
+ std(Rvalue, 0, Rindex);
+}
+
+// Store an int value at local variable slot Rindex.
+// Kills:
+// - Rindex
+void InterpreterMacroAssembler::store_local_float(FloatRegister Rvalue, Register Rindex) {
+ sldi(Rindex, Rindex, Interpreter::logStackElementSize);
+ subf(Rindex, Rindex, R18_locals);
+ stfs(Rvalue, 0, Rindex);
+}
+
+// Store an int value at local variable slot Rindex.
+// Kills:
+// - Rindex
+void InterpreterMacroAssembler::store_local_double(FloatRegister Rvalue, Register Rindex) {
+ sldi(Rindex, Rindex, Interpreter::logStackElementSize);
+ subf(Rindex, Rindex, R18_locals);
+ stfd(Rvalue, -8, Rindex);
+}
+
+// Read pending exception from thread and jump to interpreter.
+// Throw exception entry if one if pending. Fall through otherwise.
+void InterpreterMacroAssembler::check_and_forward_exception(Register Rscratch1, Register Rscratch2) {
+ assert_different_registers(Rscratch1, Rscratch2, R3);
+ Register Rexception = Rscratch1;
+ Register Rtmp = Rscratch2;
+ Label Ldone;
+ // Get pending exception oop.
+ ld(Rexception, thread_(pending_exception));
+ cmpdi(CCR0, Rexception, 0);
+ beq(CCR0, Ldone);
+ li(Rtmp, 0);
+ mr_if_needed(R3, Rexception);
+ std(Rtmp, thread_(pending_exception)); // Clear exception in thread
+ if (Interpreter::rethrow_exception_entry() != NULL) {
+ // Already got entry address.
+ load_dispatch_table(Rtmp, (address*)Interpreter::rethrow_exception_entry());
+ } else {
+ // Dynamically load entry address.
+ int simm16_rest = load_const_optimized(Rtmp, &Interpreter::_rethrow_exception_entry, R0, true);
+ ld(Rtmp, simm16_rest, Rtmp);
+ }
+ mtctr(Rtmp);
+ save_interpreter_state(Rtmp);
+ bctr();
+
+ align(32, 12);
+ bind(Ldone);
+}
+
+void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, bool check_exceptions) {
+ save_interpreter_state(R11_scratch1);
+
+ MacroAssembler::call_VM(oop_result, entry_point, false);
+
+ restore_interpreter_state(R11_scratch1, /*bcp_and_mdx_only*/ true);
+
+ check_and_handle_popframe(R11_scratch1);
+ check_and_handle_earlyret(R11_scratch1);
+ // Now check exceptions manually.
+ if (check_exceptions) {
+ check_and_forward_exception(R11_scratch1, R12_scratch2);
+ }
+}
+
+void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) {
+ // ARG1 is reserved for the thread.
+ mr_if_needed(R4_ARG2, arg_1);
+ call_VM(oop_result, entry_point, check_exceptions);
+}
+
+void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
+ // ARG1 is reserved for the thread.
+ mr_if_needed(R4_ARG2, arg_1);
+ assert(arg_2 != R4_ARG2, "smashed argument");
+ mr_if_needed(R5_ARG3, arg_2);
+ call_VM(oop_result, entry_point, check_exceptions);
+}
+
+void InterpreterMacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
+ // ARG1 is reserved for the thread.
+ mr_if_needed(R4_ARG2, arg_1);
+ assert(arg_2 != R4_ARG2, "smashed argument");
+ mr_if_needed(R5_ARG3, arg_2);
+ assert(arg_3 != R4_ARG2 && arg_3 != R5_ARG3, "smashed argument");
+ mr_if_needed(R6_ARG4, arg_3);
+ call_VM(oop_result, entry_point, check_exceptions);
+}
+
+void InterpreterMacroAssembler::save_interpreter_state(Register scratch) {
+ ld(scratch, 0, R1_SP);
+ std(R15_esp, _ijava_state_neg(esp), scratch);
+ std(R14_bcp, _ijava_state_neg(bcp), scratch);
+ std(R26_monitor, _ijava_state_neg(monitors), scratch);
+ if (ProfileInterpreter) { std(R28_mdx, _ijava_state_neg(mdx), scratch); }
+ // Other entries should be unchanged.
+}
+
+void InterpreterMacroAssembler::restore_interpreter_state(Register scratch, bool bcp_and_mdx_only) {
+ ld(scratch, 0, R1_SP);
+ ld(R14_bcp, _ijava_state_neg(bcp), scratch); // Changed by VM code (exception).
+ if (ProfileInterpreter) { ld(R28_mdx, _ijava_state_neg(mdx), scratch); } // Changed by VM code.
+ if (!bcp_and_mdx_only) {
+ // Following ones are Metadata.
+ ld(R19_method, _ijava_state_neg(method), scratch);
+ ld(R27_constPoolCache, _ijava_state_neg(cpoolCache), scratch);
+ // Following ones are stack addresses and don't require reload.
+ ld(R15_esp, _ijava_state_neg(esp), scratch);
+ ld(R18_locals, _ijava_state_neg(locals), scratch);
+ ld(R26_monitor, _ijava_state_neg(monitors), scratch);
+ }
+#ifdef ASSERT
+ {
+ Label Lok;
+ subf(R0, R1_SP, scratch);
+ cmpdi(CCR0, R0, frame::abi_reg_args_size + frame::ijava_state_size);
+ bge(CCR0, Lok);
+ stop("frame too small (restore istate)", 0x5432);
+ bind(Lok);
+ }
+ {
+ Label Lok;
+ ld(R0, _ijava_state_neg(ijava_reserved), scratch);
+ cmpdi(CCR0, R0, 0x5afe);
+ beq(CCR0, Lok);
+ stop("frame corrupted (restore istate)", 0x5afe);
+ bind(Lok);
+ }
+#endif
+}
+
+#endif // !CC_INTERP
+
void InterpreterMacroAssembler::get_method_counters(Register method,
Register Rcounters,
Label& skip) {
@@ -321,6 +1957,66 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) {
if (state == atos) { MacroAssembler::verify_oop(reg); }
}
+#ifndef CC_INTERP
+// Local helper function for the verify_oop_or_return_address macro.
+static bool verify_return_address(Method* m, int bci) {
+#ifndef PRODUCT
+ address pc = (address)(m->constMethod()) + in_bytes(ConstMethod::codes_offset()) + bci;
+ // Assume it is a valid return address if it is inside m and is preceded by a jsr.
+ if (!m->contains(pc)) return false;
+ address jsr_pc;
+ jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr);
+ if (*jsr_pc == Bytecodes::_jsr && jsr_pc >= m->code_base()) return true;
+ jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr_w);
+ if (*jsr_pc == Bytecodes::_jsr_w && jsr_pc >= m->code_base()) return true;
+#endif // PRODUCT
+ return false;
+}
+
+void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
+ if (VerifyFPU) {
+ unimplemented("verfiyFPU");
+ }
+}
+
+void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Register Rtmp) {
+ if (!VerifyOops) return;
+
+ // The VM documentation for the astore[_wide] bytecode allows
+ // the TOS to be not only an oop but also a return address.
+ Label test;
+ Label skip;
+ // See if it is an address (in the current method):
+
+ const int log2_bytecode_size_limit = 16;
+ srdi_(Rtmp, reg, log2_bytecode_size_limit);
+ bne(CCR0, test);
+
+ address fd = CAST_FROM_FN_PTR(address, verify_return_address);
+ unsigned int nbytes_save = 10*8; // 10 volatile gprs
+
+ save_LR_CR(Rtmp);
+ push_frame_reg_args(nbytes_save, Rtmp);
+ save_volatile_gprs(R1_SP, 112); // except R0
+
+ load_const_optimized(Rtmp, fd, R0);
+ mr_if_needed(R4_ARG2, reg);
+ mr(R3_ARG1, R19_method);
+ call_c(Rtmp); // call C
+
+ restore_volatile_gprs(R1_SP, 112); // except R0
+ pop_frame();
+ restore_LR_CR(Rtmp);
+ b(skip);
+
+ // Perform a more elaborate out-of-line call.
+ // Not an address; verify it:
+ bind(test);
+ verify_oop(reg);
+ bind(skip);
+}
+#endif // !CC_INTERP
+
// Inline assembly for:
//
// if (thread is in interp_only_mode) {
@@ -343,13 +2039,12 @@ void InterpreterMacroAssembler::notify_method_entry() {
cmpwi(CCR0, R0, 0);
beq(CCR0, jvmti_post_done);
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry),
- /*check_exceptions=*/false);
+ /*check_exceptions=*/true CC_INTERP_ONLY(&& false));
bind(jvmti_post_done);
}
}
-
// Inline assembly for:
//
// if (thread is in interp_only_mode) {
@@ -365,26 +2060,33 @@ void InterpreterMacroAssembler::notify_method_entry() {
//
// Native methods have their result stored in d_tmp and l_tmp.
// Java methods have their result stored in the expression stack.
-void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state) {
+void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, TosState state,
+ NotifyMethodExitMode mode, bool check_exceptions) {
// JVMTI
// Whenever JVMTI puts a thread in interp_only_mode, method
// entry/exit events are sent for that thread to track stack
// depth. If it is possible to enter interp_only_mode we add
// the code to check if the event should be sent.
- if (JvmtiExport::can_post_interpreter_events()) {
+ if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) {
Label jvmti_post_done;
lwz(R0, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread);
cmpwi(CCR0, R0, 0);
beq(CCR0, jvmti_post_done);
+ CC_INTERP_ONLY(assert(is_native_method && !check_exceptions, "must not push state"));
+ if (!is_native_method) push(state); // Expose tos to GC.
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit),
- /*check_exceptions=*/false);
+ /*check_exceptions=*/check_exceptions);
+ if (!is_native_method) pop(state);
align(32, 12);
bind(jvmti_post_done);
}
+
+ // Dtrace support not implemented.
}
+#ifdef CC_INTERP
// Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME
// (using parent_frame_resize) and push a new interpreter
// TOP_IJAVA_FRAME (using frame_size).
@@ -442,7 +2144,6 @@ void InterpreterMacroAssembler::pop_interpreter_frame(Register tmp1, Register tm
std(R1_SP, _top_ijava_frame_abi(top_frame_sp), R1_SP);
}
-#ifdef CC_INTERP
// Turn state's interpreter frame into the current TOP_IJAVA_FRAME.
void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, Register tmp1, Register tmp2, Register tmp3) {
assert_different_registers(R14_state, R15_prev_state, tmp1, tmp2, tmp3);
@@ -471,7 +2172,6 @@ void InterpreterMacroAssembler::pop_interpreter_frame_to_state(Register state, R
// Used for non-initial callers by unextended_sp().
std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP);
}
-#endif // CC_INTERP
// Set SP to initial caller's sp, but before fix the back chain.
void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Register tmp2) {
@@ -481,7 +2181,6 @@ void InterpreterMacroAssembler::resize_frame_to_initial_caller(Register tmp1, Re
mr(R1_SP, tmp1); // ... and resize to initial caller.
}
-#ifdef CC_INTERP
// Pop the current interpreter state (without popping the correspoding
// frame) and restore R14_state and R15_prev_state accordingly.
// Use prev_state_may_be_0 to indicate whether prev_state may be 0
diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp
index a189e30043c..9846bb5113e 100644
--- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp
+++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
#include "assembler_ppc.inline.hpp"
#include "interpreter/invocationCounter.hpp"
-// This file specializes the assembler with interpreter-specific macros
+// This file specializes the assembler with interpreter-specific macros.
class InterpreterMacroAssembler: public MacroAssembler {
@@ -39,15 +39,176 @@ class InterpreterMacroAssembler: public MacroAssembler {
void null_check_throw(Register a, int offset, Register temp_reg);
- // Handy address generation macros
+ void branch_to_entry(address entry, Register Rscratch);
+
+ // Handy address generation macros.
#define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread
#define method_(field_name) in_bytes(Method::field_name ## _offset()), R19_method
#ifdef CC_INTERP
#define state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R14_state
#define prev_state_(field_name) in_bytes(byte_offset_of(BytecodeInterpreter, field_name)), R15_prev_state
+ void pop (TosState state) {}; // Not needed.
+ void push(TosState state) {}; // Not needed.
#endif
+#ifndef CC_INTERP
+ virtual void check_and_handle_popframe(Register java_thread);
+ virtual void check_and_handle_earlyret(Register java_thread);
+
+ // Base routine for all dispatches.
+ void dispatch_base(TosState state, address* table);
+
+ void load_earlyret_value(TosState state, Register Rscratch1);
+
+ static const Address l_tmp;
+ static const Address d_tmp;
+
+ // dispatch routines
+ void dispatch_next(TosState state, int step = 0);
+ void dispatch_via (TosState state, address* table);
+ void load_dispatch_table(Register dst, address* table);
+ void dispatch_Lbyte_code(TosState state, Register bytecode, address* table, bool verify = false);
+
+ // Called by shared interpreter generator.
+ void dispatch_prolog(TosState state, int step = 0);
+ void dispatch_epilog(TosState state, int step = 0);
+
+ // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls.
+ void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1);
+ void super_call_VM(Register thread_cache, Register oop_result, Register last_java_sp,
+ address entry_point, Register arg_1, Register arg_2, bool check_exception = true);
+
+ // Generate a subtype check: branch to ok_is_subtype if sub_klass is
+ // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3.
+ void gen_subtype_check(Register sub_klass, Register super_klass,
+ Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype);
+
+ // Load object from cpool->resolved_references(index).
+ void load_resolved_reference_at_index(Register result, Register index);
+
+ void generate_stack_overflow_check_with_compare_and_throw(Register Rmem_frame_size, Register Rscratch1);
+ void load_receiver(Register Rparam_count, Register Rrecv_dst);
+
+ // helpers for expression stack
+ void pop_i( Register r = R17_tos);
+ void pop_ptr( Register r = R17_tos);
+ void pop_l( Register r = R17_tos);
+ void pop_f(FloatRegister f = F15_ftos);
+ void pop_d(FloatRegister f = F15_ftos );
+
+ void push_i( Register r = R17_tos);
+ void push_ptr( Register r = R17_tos);
+ void push_l( Register r = R17_tos);
+ void push_f(FloatRegister f = F15_ftos );
+ void push_d(FloatRegister f = F15_ftos);
+
+ void push_2ptrs(Register first, Register second);
+
+ void push_l_pop_d(Register l = R17_tos, FloatRegister d = F15_ftos);
+ void push_d_pop_l(FloatRegister d = F15_ftos, Register l = R17_tos);
+
+ void pop (TosState state); // transition vtos -> state
+ void push(TosState state); // transition state -> vtos
+ void empty_expression_stack(); // Resets both Lesp and SP.
+
+ public:
+ // Load values from bytecode stream:
+
+ enum signedOrNot { Signed, Unsigned };
+ enum setCCOrNot { set_CC, dont_set_CC };
+
+ void get_2_byte_integer_at_bcp(int bcp_offset,
+ Register Rdst,
+ signedOrNot is_signed);
+
+ void get_4_byte_integer_at_bcp(int bcp_offset,
+ Register Rdst,
+ signedOrNot is_signed = Unsigned);
+
+ void get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size);
+
+ void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2));
+
+
+ // common code
+
+ void field_offset_at(int n, Register tmp, Register dest, Register base);
+ int field_offset_at(Register object, address bcp, int offset);
+ void fast_iaaccess(int n, address bcp);
+ void fast_iagetfield(address bcp);
+ void fast_iaputfield(address bcp, bool do_store_check);
+
+ void index_check(Register array, Register index, int index_shift, Register tmp, Register res);
+ void index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res);
+
+ void get_const(Register Rdst);
+ void get_constant_pool(Register Rdst);
+ void get_constant_pool_cache(Register Rdst);
+ void get_cpool_and_tags(Register Rcpool, Register Rtags);
+ void is_a(Label& L);
+
+ // Java Call Helpers
+ void call_from_interpreter(Register Rtarget_method, Register Rret_addr, Register Rscratch1, Register Rscratch2);
+
+ // --------------------------------------------------
+
+ void unlock_if_synchronized_method(TosState state, bool throw_monitor_exception = true,
+ bool install_monitor_exception = true);
+
+ // Removes the current activation (incl. unlocking of monitors).
+ // Additionally this code is used for earlyReturn in which case we
+ // want to skip throwing an exception and installing an exception.
+ void remove_activation(TosState state,
+ bool throw_monitor_exception = true,
+ bool install_monitor_exception = true);
+ void merge_frames(Register Rtop_frame_sp, Register return_pc, Register Rscratch1, Register Rscratch2); // merge top frames
+
+ void add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2);
+
+ // Local variable access helpers
+ void load_local_int(Register Rdst_value, Register Rdst_address, Register Rindex);
+ void load_local_long(Register Rdst_value, Register Rdst_address, Register Rindex);
+ void load_local_ptr(Register Rdst_value, Register Rdst_address, Register Rindex);
+ void load_local_float(FloatRegister Rdst_value, Register Rdst_address, Register Rindex);
+ void load_local_double(FloatRegister Rdst_value, Register Rdst_address, Register Rindex);
+ void store_local_int(Register Rvalue, Register Rindex);
+ void store_local_long(Register Rvalue, Register Rindex);
+ void store_local_ptr(Register Rvalue, Register Rindex);
+ void store_local_float(FloatRegister Rvalue, Register Rindex);
+ void store_local_double(FloatRegister Rvalue, Register Rindex);
+
+ // Call VM for std frames
+ // Special call VM versions that check for exceptions and forward exception
+ // via short cut (not via expensive forward exception stub).
+ void check_and_forward_exception(Register Rscratch1, Register Rscratch2);
+ void call_VM(Register oop_result, address entry_point, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
+ // Should not be used:
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, bool check_exceptions = true) {ShouldNotReachHere();}
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true) {ShouldNotReachHere();}
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true) {ShouldNotReachHere();}
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true) {ShouldNotReachHere();}
+
+ Address first_local_in_stack();
+
+ enum LoadOrStore { load, store };
+ void static_iload_or_store(int which_local, LoadOrStore direction, Register Rtmp);
+ void static_aload_or_store(int which_local, LoadOrStore direction, Register Rtmp);
+ void static_dload_or_store(int which_local, LoadOrStore direction);
+
+ void save_interpreter_state(Register scratch);
+ void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false);
+
+ void increment_backedge_counter(const Register Rcounters, Register Rtmp, Register Rtmp2, Register Rscratch);
+ void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp);
+
+ void record_static_call_in_profile(Register Rentry, Register Rtmp);
+ void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp);
+#endif // !CC_INTERP
+
void get_method_counters(Register method, Register Rcounters, Label& skip);
void increment_invocation_counter(Register iv_be_count, Register Rtmp1, Register Rtmp2_r0);
@@ -55,12 +216,59 @@ class InterpreterMacroAssembler: public MacroAssembler {
void lock_object (Register lock_reg, Register obj_reg);
void unlock_object(Register lock_reg, bool check_for_exceptions = true);
+#ifndef CC_INTERP
+
+ // Interpreter profiling operations
+ void set_method_data_pointer_for_bcp();
+ void test_method_data_pointer(Label& zero_continue);
+ void verify_method_data_pointer();
+ void test_invocation_counter_for_mdp(Register invocation_count, Register Rscratch, Label &profile_continue);
+
+ void set_mdp_data_at(int constant, Register value);
+
+ void increment_mdp_data_at(int constant, Register counter_addr, Register Rbumped_count, bool decrement = false);
+
+ void increment_mdp_data_at(Register counter_addr, Register Rbumped_count, bool decrement = false);
+ void increment_mdp_data_at(Register reg, int constant, Register scratch, Register Rbumped_count, bool decrement = false);
+
+ void set_mdp_flag_at(int flag_constant, Register scratch);
+ void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, Register test_out);
+
+ void update_mdp_by_offset(int offset_of_disp, Register scratch);
+ void update_mdp_by_offset(Register reg, int offset_of_disp,
+ Register scratch);
+ void update_mdp_by_constant(int constant);
+ void update_mdp_for_ret(TosState state, Register return_bci);
+
+ void profile_taken_branch(Register scratch, Register bumped_count);
+ void profile_not_taken_branch(Register scratch1, Register scratch2);
+ void profile_call(Register scratch1, Register scratch2);
+ void profile_final_call(Register scratch1, Register scratch2);
+ void profile_virtual_call(Register Rreceiver, Register Rscratch1, Register Rscratch2, bool receiver_can_be_null);
+ void profile_typecheck(Register Rklass, Register Rscratch1, Register Rscratch2);
+ void profile_typecheck_failed(Register Rscratch1, Register Rscratch2);
+ void profile_ret(TosState state, Register return_bci, Register scratch1, Register scratch2);
+ void profile_switch_default(Register scratch1, Register scratch2);
+ void profile_switch_case(Register index, Register scratch1,Register scratch2, Register scratch3);
+ void profile_null_seen(Register Rscratch1, Register Rscratch2);
+ void record_klass_in_profile(Register receiver, Register scratch1, Register scratch2, bool is_virtual_call);
+ void record_klass_in_profile_helper(Register receiver, Register scratch1, Register scratch2, int start_row, Label& done, bool is_virtual_call);
+
+#endif // !CC_INTERP
+
// Debugging
void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos
+#ifndef CC_INTERP
+ void verify_oop_or_return_address(Register reg, Register rtmp); // for astore
+ void verify_FPU(int stack_depth, TosState state = ftos);
+#endif // !CC_INTERP
- // support for jvmdi/jvmpi
+ typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode;
+
+ // Support for jvmdi/jvmpi.
void notify_method_entry();
- void notify_method_exit(bool is_native_method, TosState state);
+ void notify_method_exit(bool is_native_method, TosState state,
+ NotifyMethodExitMode mode, bool check_exceptions);
#ifdef CC_INTERP
// Convert the current TOP_IJAVA_FRAME into a PARENT_IJAVA_FRAME
diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
index 03e1b1e7d54..80bfc2d2918 100644
--- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -51,10 +51,6 @@
#include "c1/c1_Runtime1.hpp"
#endif
-#ifndef CC_INTERP
-#error "CC_INTERP must be defined on PPC"
-#endif
-
#define __ _masm->
#ifdef PRODUCT
@@ -147,7 +143,8 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() {
#ifdef CC_INTERP
__ ld(R19_method, state_(_method));
#else
- __ unimplemented("slow signature handler 1");
+ __ ld(R19_method, 0, target_sp);
+ __ ld(R19_method, _ijava_state_neg(method), R19_method);
#endif
// Get the result handler.
@@ -157,7 +154,8 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() {
#ifdef CC_INTERP
__ ld(R19_method, state_(_method));
#else
- __ unimplemented("slow signature handler 2");
+ __ ld(R19_method, 0, target_sp);
+ __ ld(R19_method, _ijava_state_neg(method), R19_method);
#endif
{
@@ -453,7 +451,7 @@ address InterpreterGenerator::generate_abstract_entry(void) {
//
// Registers alive
// R16_thread - JavaThread*
- // R19_method - callee's methodOop (method to be invoked)
+ // R19_method - callee's method (method to be invoked)
// R1_SP - SP prepared such that caller's outgoing args are near top
// LR - return address to caller
//
@@ -491,7 +489,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
// Return to frame manager, it will handle the pending exception.
__ blr();
#else
- Unimplemented();
+ // We don't know our caller, so jump to the general forward exception stub,
+ // which will also pop our full frame off. Satisfy the interface of
+ // SharedRuntime::generate_forward_exception()
+ __ load_const_optimized(R11_scratch1, StubRoutines::forward_exception_entry(), R0);
+ __ mtctr(R11_scratch1);
+ __ bctr();
#endif
return entry;
@@ -500,8 +503,9 @@ address InterpreterGenerator::generate_abstract_entry(void) {
// Call an accessor method (assuming it is resolved, otherwise drop into
// vanilla (slow path) entry.
address InterpreterGenerator::generate_accessor_entry(void) {
- if(!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods)))
+ if (!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) {
return NULL;
+ }
Label Lslow_path, Lacquire;
@@ -586,10 +590,14 @@ address InterpreterGenerator::generate_accessor_entry(void) {
// Load from branch table and dispatch (volatile case: one instruction ahead)
__ sldi(Rflags, Rflags, LogBytesPerWord);
__ cmpwi(CCR6, Rscratch, 1); // volatile?
- __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0
+ }
__ ldx(Rbtable, Rbtable, Rflags);
- __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point
+ }
__ mtctr(Rbtable);
__ bctr();
@@ -605,7 +613,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
}
assert(all_uninitialized != all_initialized, "consistency"); // either or
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
if (branch_table[vtos] == 0) branch_table[vtos] = __ pc(); // non-volatile_entry point
if (branch_table[dtos] == 0) branch_table[dtos] = __ pc(); // non-volatile_entry point
if (branch_table[ftos] == 0) branch_table[ftos] = __ pc(); // non-volatile_entry point
@@ -614,7 +622,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[itos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[itos] = __ pc(); // non-volatile_entry point
__ lwax(R3_RET, Rclass_or_obj, Roffset);
__ beq(CCR6, Lacquire);
@@ -623,7 +631,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[ltos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[ltos] = __ pc(); // non-volatile_entry point
__ ldx(R3_RET, Rclass_or_obj, Roffset);
__ beq(CCR6, Lacquire);
@@ -632,7 +640,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[btos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[btos] = __ pc(); // non-volatile_entry point
__ lbzx(R3_RET, Rclass_or_obj, Roffset);
__ extsb(R3_RET, R3_RET);
@@ -642,7 +650,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[ctos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[ctos] = __ pc(); // non-volatile_entry point
__ lhzx(R3_RET, Rclass_or_obj, Roffset);
__ beq(CCR6, Lacquire);
@@ -651,7 +659,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[stos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[stos] = __ pc(); // non-volatile_entry point
__ lhax(R3_RET, Rclass_or_obj, Roffset);
__ beq(CCR6, Lacquire);
@@ -660,7 +668,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
if (branch_table[atos] == 0) { // generate only once
__ align(32, 28, 28); // align load
- __ sync(); // volatile entry point (one instruction before non-volatile_entry point)
+ __ fence(); // volatile entry point (one instruction before non-volatile_entry point)
branch_table[atos] = __ pc(); // non-volatile_entry point
__ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rclass_or_obj);
__ verify_oop(R3_RET);
@@ -683,10 +691,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
#endif
__ bind(Lslow_path);
- assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now");
- __ load_const_optimized(Rscratch, Interpreter::entry_for_kind(Interpreter::zerolocals), R0);
- __ mtctr(Rscratch);
- __ bctr();
+ __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), Rscratch);
__ flush();
return entry;
@@ -773,10 +778,7 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
// Generate regular method entry.
__ bind(slow_path);
- assert(Interpreter::entry_for_kind(Interpreter::zerolocals), "Normal entry must have been generated by now");
- __ load_const_optimized(R11_scratch1, Interpreter::entry_for_kind(Interpreter::zerolocals), R0);
- __ mtctr(R11_scratch1);
- __ bctr();
+ __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1);
__ flush();
return entry;
diff --git a/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp
index 37bf8e9fe6b..48864ae7213 100644
--- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,15 +28,23 @@
public:
- // Stack index relative to tos (which points at value)
+ // Stack index relative to tos (which points at value).
static int expr_index_at(int i) {
return stackElementWords * i;
}
- // Already negated by c++ interpreter
+ // Already negated by c++ interpreter.
static int local_index_at(int i) {
assert(i <= 0, "local direction already negated");
return stackElementWords * i;
}
+#ifndef CC_INTERP
+ // The offset in bytes to access a expression stack slot
+ // relative to the esp pointer.
+ static int expr_offset_in_bytes(int slot) {
+ return stackElementSize * slot + wordSize;
+ }
+#endif
+
#endif // CPU_PPC_VM_INTERPRETER_PPC_PP
diff --git a/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp b/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp
index f12df9cbe76..26ca0dbf181 100644
--- a/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/javaFrameAnchor_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,6 @@
#ifndef CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP
#define CPU_PPC_VM_JAVAFRAMEANCHOR_PPC_HPP
-#ifndef CC_INTERP
-#error "CC_INTERP must be defined on PPC64"
-#endif
-
public:
// Each arch must define reset, save, restore
// These are used by objects that only care about:
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
index 603e3ed2592..2d3d9cf9713 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp
@@ -2412,7 +2412,8 @@ void MacroAssembler::set_top_ijava_frame_at_SP_as_last_Java_frame(Register sp, R
#ifdef CC_INTERP
ld(tmp1/*pc*/, _top_ijava_frame_abi(frame_manager_lr), sp);
#else
- Unimplemented();
+ address entry = pc();
+ load_const_optimized(tmp1, entry);
#endif
set_last_Java_frame(/*sp=*/sp, /*pc=*/tmp1);
@@ -2472,6 +2473,16 @@ void MacroAssembler::store_klass(Register dst_oop, Register klass, Register ck)
}
}
+void MacroAssembler::store_klass_gap(Register dst_oop, Register val) {
+ if (UseCompressedClassPointers) {
+ if (val == noreg) {
+ val = R0;
+ li(val, 0);
+ }
+ stw(val, oopDesc::klass_gap_offset_in_bytes(), dst_oop); // klass gap if compressed
+ }
+}
+
int MacroAssembler::instr_size_for_decode_klass_not_null() {
if (!UseCompressedClassPointers) return 0;
int num_instrs = 1; // shift or move
@@ -3143,3 +3154,15 @@ void MacroAssembler::zap_from_to(Register low, int before, Register high, int af
}
#endif // !PRODUCT
+
+SkipIfEqualZero::SkipIfEqualZero(MacroAssembler* masm, Register temp, const bool* flag_addr) : _masm(masm), _label() {
+ int simm16_offset = masm->load_const_optimized(temp, (address)flag_addr, R0, true);
+ assert(sizeof(bool) == 1, "PowerPC ABI");
+ masm->lbz(temp, simm16_offset, temp);
+ masm->cmpwi(CCR0, temp, 0);
+ masm->beq(CCR0, _label);
+}
+
+SkipIfEqualZero::~SkipIfEqualZero() {
+ _masm->bind(_label);
+}
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
index 9b793ef1547..a6576a4c472 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -566,12 +566,14 @@ class MacroAssembler: public Assembler {
// Load heap oop and decompress. Loaded oop may not be null.
inline void load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1 = noreg);
+ inline void store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1,
+ /*specify if d must stay uncompressed*/ Register tmp = noreg);
// Null allowed.
inline void load_heap_oop(Register d, RegisterOrConstant offs, Register s1 = noreg);
// Encode/decode heap oop. Oop may not be null, else en/decoding goes wrong.
- inline void encode_heap_oop_not_null(Register d);
+ inline Register encode_heap_oop_not_null(Register d, Register src = noreg);
inline void decode_heap_oop_not_null(Register d);
// Null allowed.
@@ -581,6 +583,7 @@ class MacroAssembler: public Assembler {
void load_klass(Register dst, Register src);
void load_klass_with_trap_null_check(Register dst, Register src);
void store_klass(Register dst_oop, Register klass, Register tmp = R0);
+ void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified.
static int instr_size_for_decode_klass_not_null();
void decode_klass_not_null(Register dst, Register src = noreg);
void encode_klass_not_null(Register dst, Register src = noreg);
@@ -693,4 +696,21 @@ class MacroAssembler: public Assembler {
void zap_from_to(Register low, int before, Register high, int after, Register val, Register addr) PRODUCT_RETURN;
};
+// class SkipIfEqualZero:
+//
+// Instantiating this class will result in assembly code being output that will
+// jump around any code emitted between the creation of the instance and it's
+// automatic destruction at the end of a scope block, depending on the value of
+// the flag passed to the constructor, which will be checked at run-time.
+class SkipIfEqualZero : public StackObj {
+ private:
+ MacroAssembler* _masm;
+ Label _label;
+
+ public:
+ // 'Temp' is a temp register that this object can use (and trash).
+ explicit SkipIfEqualZero(MacroAssembler*, Register temp, const bool* flag_addr);
+ ~SkipIfEqualZero();
+};
+
#endif // CPU_PPC_VM_MACROASSEMBLER_PPC_HPP
diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
index bebfb4b6305..84485d4f6af 100644
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -321,6 +321,15 @@ inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstan
}
}
+inline void MacroAssembler::store_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) {
+ if (UseCompressedOops) {
+ Register compressedOop = encode_heap_oop_not_null((tmp != noreg) ? tmp : d, d);
+ stw(compressedOop, offs, s1);
+ } else {
+ std(d, offs, s1);
+ }
+}
+
inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1) {
if (UseCompressedOops) {
lwz(d, offs, s1);
@@ -330,13 +339,17 @@ inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, R
}
}
-inline void MacroAssembler::encode_heap_oop_not_null(Register d) {
+inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register src) {
+ Register current = (src!=noreg) ? src : d; // Compressed oop is in d if no src provided.
if (Universe::narrow_oop_base() != NULL) {
- sub(d, d, R30);
+ sub(d, current, R30);
+ current = d;
}
if (Universe::narrow_oop_shift() != 0) {
- srdi(d, d, LogMinObjAlignmentInBytes);
+ srdi(d, current, LogMinObjAlignmentInBytes);
+ current = d;
}
+ return current; // Encoded oop is in this register.
}
inline void MacroAssembler::decode_heap_oop_not_null(Register d) {
diff --git a/hotspot/src/cpu/ppc/vm/register_ppc.hpp b/hotspot/src/cpu/ppc/vm/register_ppc.hpp
index bc04d8d2c16..107c5bab8b8 100644
--- a/hotspot/src/cpu/ppc/vm/register_ppc.hpp
+++ b/hotspot/src/cpu/ppc/vm/register_ppc.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -579,15 +579,27 @@ REGISTER_DECLARATION(FloatRegister, F13_ARG13, F13); // volatile
// Register declarations to be used in frame manager assembly code.
// Use only non-volatile registers in order to keep values across C-calls.
+#ifdef CC_INTERP
REGISTER_DECLARATION(Register, R14_state, R14); // address of new cInterpreter.
REGISTER_DECLARATION(Register, R15_prev_state, R15); // address of old cInterpreter
+#else // CC_INTERP
+REGISTER_DECLARATION(Register, R14_bcp, R14);
+REGISTER_DECLARATION(Register, R15_esp, R15);
+REGISTER_DECLARATION(FloatRegister, F15_ftos, F15);
+#endif // CC_INTERP
REGISTER_DECLARATION(Register, R16_thread, R16); // address of current thread
REGISTER_DECLARATION(Register, R17_tos, R17); // address of Java tos (prepushed).
REGISTER_DECLARATION(Register, R18_locals, R18); // address of first param slot (receiver).
REGISTER_DECLARATION(Register, R19_method, R19); // address of current method
#ifndef DONT_USE_REGISTER_DEFINES
+#ifdef CC_INTERP
#define R14_state AS_REGISTER(Register, R14)
#define R15_prev_state AS_REGISTER(Register, R15)
+#else // CC_INTERP
+#define R14_bcp AS_REGISTER(Register, R14)
+#define R15_esp AS_REGISTER(Register, R15)
+#define F15_ftos AS_REGISTER(FloatRegister, F15)
+#endif // CC_INTERP
#define R16_thread AS_REGISTER(Register, R16)
#define R17_tos AS_REGISTER(Register, R17)
#define R18_locals AS_REGISTER(Register, R18)
@@ -608,6 +620,14 @@ REGISTER_DECLARATION(Register, R26_tmp6, R26);
REGISTER_DECLARATION(Register, R27_tmp7, R27);
REGISTER_DECLARATION(Register, R28_tmp8, R28);
REGISTER_DECLARATION(Register, R29_tmp9, R29);
+#ifndef CC_INTERP
+REGISTER_DECLARATION(Register, R24_dispatch_addr, R24);
+REGISTER_DECLARATION(Register, R25_templateTableBase, R25);
+REGISTER_DECLARATION(Register, R26_monitor, R26);
+REGISTER_DECLARATION(Register, R27_constPoolCache, R27);
+REGISTER_DECLARATION(Register, R28_mdx, R28);
+#endif // CC_INTERP
+
#ifndef DONT_USE_REGISTER_DEFINES
#define R21_tmp1 AS_REGISTER(Register, R21)
#define R22_tmp2 AS_REGISTER(Register, R22)
@@ -618,6 +638,16 @@ REGISTER_DECLARATION(Register, R29_tmp9, R29);
#define R27_tmp7 AS_REGISTER(Register, R27)
#define R28_tmp8 AS_REGISTER(Register, R28)
#define R29_tmp9 AS_REGISTER(Register, R29)
+#ifndef CC_INTERP
+// Lmonitors : monitor pointer
+// LcpoolCache: constant pool cache
+// mdx: method data index
+#define R24_dispatch_addr AS_REGISTER(Register, R24)
+#define R25_templateTableBase AS_REGISTER(Register, R25)
+#define R26_monitor AS_REGISTER(Register, R26)
+#define R27_constPoolCache AS_REGISTER(Register, R27)
+#define R28_mdx AS_REGISTER(Register, R28)
+#endif
#define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4)
#endif
diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
index 323bdf46771..d556d7009fa 100644
--- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -957,6 +957,9 @@ static address gen_c2i_adapter(MacroAssembler *masm,
#ifdef CC_INTERP
const Register tos = R17_tos;
+#else
+ const Register tos = R15_esp;
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
#endif
// load TOS
@@ -975,7 +978,7 @@ static void gen_i2c_adapter(MacroAssembler *masm,
const BasicType *sig_bt,
const VMRegPair *regs) {
- // Load method's entry-point from methodOop.
+ // Load method's entry-point from method.
__ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
__ mtctr(R12_scratch2);
@@ -996,7 +999,10 @@ static void gen_i2c_adapter(MacroAssembler *masm,
#ifdef CC_INTERP
const Register ld_ptr = R17_tos;
+#else
+ const Register ld_ptr = R15_esp;
#endif
+
const Register value_regs[] = { R22_tmp2, R23_tmp3, R24_tmp4, R25_tmp5, R26_tmp6 };
const int num_value_regs = sizeof(value_regs) / sizeof(Register);
int value_regs_index = 0;
@@ -1087,8 +1093,8 @@ static void gen_i2c_adapter(MacroAssembler *masm,
}
}
- BLOCK_COMMENT("Store method oop");
- // Store method oop into thread->callee_target.
+ BLOCK_COMMENT("Store method");
+ // Store method into thread->callee_target.
// We might end up in handle_wrong_method if the callee is
// deoptimized as we race thru here. If that happens we don't want
// to take a safepoint because the caller frame will look
@@ -2617,8 +2623,12 @@ static void push_skeleton_frame(MacroAssembler* masm, bool deopt,
#ifdef CC_INTERP
__ std(R1_SP, _parent_ijava_frame_abi(initial_caller_sp), R1_SP);
#else
- Unimplemented();
+#ifdef ASSERT
+ __ load_const_optimized(pc_reg, 0x5afe);
+ __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP);
#endif
+ __ std(R1_SP, _ijava_state_neg(sender_sp), R1_SP);
+#endif // CC_INTERP
__ addi(number_of_frames_reg, number_of_frames_reg, -1);
__ addi(frame_sizes_reg, frame_sizes_reg, wordSize);
__ addi(pcs_reg, pcs_reg, wordSize);
@@ -2690,7 +2700,15 @@ static void push_skeleton_frames(MacroAssembler* masm, bool deopt,
__ std(R12_scratch2, _abi(lr), R1_SP);
// Initialize initial_caller_sp.
+#ifdef CC_INTERP
__ std(frame_size_reg/*old_sp*/, _parent_ijava_frame_abi(initial_caller_sp), R1_SP);
+#else
+#ifdef ASSERT
+ __ load_const_optimized(pc_reg, 0x5afe);
+ __ std(pc_reg, _ijava_state_neg(ijava_reserved), R1_SP);
+#endif
+ __ std(frame_size_reg, _ijava_state_neg(sender_sp), R1_SP);
+#endif // CC_INTERP
#ifdef ASSERT
// Make sure that there is at least one entry in the array.
@@ -2911,10 +2929,16 @@ void SharedRuntime::generate_deopt_blob() {
// optional c2i, caller of deoptee, ...).
// Initialize R14_state.
+#ifdef CC_INTERP
__ ld(R14_state, 0, R1_SP);
__ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes());
// Also inititialize R15_prev_state.
__ restore_prev_state();
+#else
+ __ restore_interpreter_state(R11_scratch1);
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
+#endif // CC_INTERP
+
// Return to the interpreter entry point.
__ blr();
@@ -3033,11 +3057,17 @@ void SharedRuntime::generate_uncommon_trap_blob() {
// stack: (top interpreter frame, ..., optional interpreter frame,
// optional c2i, caller of deoptee, ...).
+#ifdef CC_INTERP
// Initialize R14_state, ...
__ ld(R11_scratch1, 0, R1_SP);
__ addi(R14_state, R11_scratch1, -frame::interpreter_frame_cinterpreterstate_size_in_bytes());
// also initialize R15_prev_state.
__ restore_prev_state();
+#else
+ __ restore_interpreter_state(R11_scratch1);
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
+#endif // CC_INTERP
+
// Return to the interpreter entry point.
__ blr();
@@ -3115,7 +3145,6 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
frame_size_in_bytes,
/*restore_ctr=*/true);
-
BLOCK_COMMENT(" Jump to forward_exception_entry.");
// Jump to forward_exception_entry, with the issuing PC in LR
// so it looks like the original nmethod called forward_exception_entry.
@@ -3200,7 +3229,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
RegisterSaver::restore_live_registers_and_pop_frame(masm, frame_size_in_bytes, /*restore_ctr*/ false);
- // Get the returned methodOop.
+ // Get the returned method.
__ get_vm_result_2(R19_method);
__ bctr();
diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
index 96c3ae94648..d452b27038c 100644
--- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
+++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2012, 2013 SAP AG. All rights reserved.
+ * Copyright 2012, 2014 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,15 +39,10 @@
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_OS_FAMILY_aix
-# include "thread_aix.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
+#include "runtime/thread.inline.hpp"
#define __ _masm->
@@ -221,7 +216,7 @@ class StubGenerator: public StubCodeGenerator {
{
BLOCK_COMMENT("Call frame manager or native entry.");
// Call frame manager or native entry.
- Register r_new_arg_entry = R14_state;
+ Register r_new_arg_entry = R14; // PPC_state;
assert_different_registers(r_new_arg_entry, r_top_of_arguments_addr,
r_arg_method, r_arg_thread);
@@ -234,7 +229,11 @@ class StubGenerator: public StubCodeGenerator {
// R16_thread - JavaThread*
// Tos must point to last argument - element_size.
+#ifdef CC_INTERP
const Register tos = R17_tos;
+#else
+ const Register tos = R15_esp;
+#endif
__ addi(tos, r_top_of_arguments_addr, -Interpreter::stackElementSize);
// initialize call_stub locals (step 2)
@@ -248,8 +247,11 @@ class StubGenerator: public StubCodeGenerator {
assert(tos != r_arg_thread && R19_method != r_arg_thread, "trashed r_arg_thread");
// Set R15_prev_state to 0 for simplifying checks in callee.
+#ifdef CC_INTERP
__ li(R15_prev_state, 0);
-
+#else
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
+#endif
// Stack on entry to frame manager / native entry:
//
// F0 [TOP_IJAVA_FRAME_ABI]
@@ -2089,7 +2091,7 @@ class StubGenerator: public StubCodeGenerator {
guarantee(!UseAESIntrinsics, "not yet implemented.");
}
- // PPC uses stubs for safefetch.
+ // Safefetch stubs.
generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
&StubRoutines::_safefetch32_fault_pc,
&StubRoutines::_safefetch32_continuation_pc);
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp
new file mode 100644
index 00000000000..051ed26e728
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP
+#define CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP
+
+ protected:
+ address generate_normal_entry(bool synchronized);
+ address generate_native_entry(bool synchronized);
+ address generate_math_entry(AbstractInterpreter::MethodKind kind);
+ address generate_empty_entry(void);
+
+ void lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded=false);
+ void unlock_method(bool check_exceptions = true);
+
+ void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue);
+ void generate_counter_overflow(Label& continue_entry);
+
+ void generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals);
+ void generate_stack_overflow_check(Register Rframe_size, Register Rscratch1);
+
+#endif // CPU_PPC_VM_TEMPLATEINTERPRETERGENERATOR_PPC_HPP
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
new file mode 100644
index 00000000000..2e19fca081d
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp
@@ -0,0 +1,1813 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#ifndef CC_INTERP
+#include "asm/macroAssembler.inline.hpp"
+#include "interpreter/bytecodeHistogram.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterGenerator.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateTable.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/methodData.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/jvmtiExport.hpp"
+#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vframeArray.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/macros.hpp"
+
+#undef __
+#define __ _masm->
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#else
+#define BLOCK_COMMENT(str) __ block_comment(str)
+#endif
+
+#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
+
+//-----------------------------------------------------------------------------
+
+// Actually we should never reach here since we do stack overflow checks before pushing any frame.
+address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
+ address entry = __ pc();
+ __ unimplemented("generate_StackOverflowError_handler");
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
+ address entry = __ pc();
+ __ empty_expression_stack();
+ __ load_const_optimized(R4_ARG2, (address) name);
+ // Index is in R17_tos.
+ __ mr(R5_ARG3, R17_tos);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException));
+ return entry;
+}
+
+#if 0
+// Call special ClassCastException constructor taking object to cast
+// and target class as arguments.
+address TemplateInterpreterGenerator::generate_ClassCastException_verbose_handler(const char* name) {
+ address entry = __ pc();
+
+ // Target class oop is in register R6_ARG4 by convention!
+
+ // Expression stack must be empty before entering the VM if an
+ // exception happened.
+ __ empty_expression_stack();
+ // Setup parameters.
+ // Thread will be loaded to R3_ARG1.
+ __ load_const_optimized(R4_ARG2, (address) name);
+ __ mr(R5_ARG3, R17_tos);
+ // R6_ARG4 contains specified class.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException_verbose));
+#ifdef ASSERT
+ // Above call must not return here since exception pending.
+ __ should_not_reach_here();
+#endif
+ return entry;
+}
+#endif
+
+address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
+ address entry = __ pc();
+ // Expression stack must be empty before entering the VM if an
+ // exception happened.
+ __ empty_expression_stack();
+
+ // Load exception object.
+ // Thread will be loaded to R3_ARG1.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ClassCastException), R17_tos);
+#ifdef ASSERT
+ // Above call must not return here since exception pending.
+ __ should_not_reach_here();
+#endif
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
+ address entry = __ pc();
+ //__ untested("generate_exception_handler_common");
+ Register Rexception = R17_tos;
+
+ // Expression stack must be empty before entering the VM if an exception happened.
+ __ empty_expression_stack();
+
+ __ load_const_optimized(R4_ARG2, (address) name, R11_scratch1);
+ if (pass_oop) {
+ __ mr(R5_ARG3, Rexception);
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), false);
+ } else {
+ __ load_const_optimized(R5_ARG3, (address) message, R11_scratch1);
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), false);
+ }
+
+ // Throw exception.
+ __ mr(R3_ARG1, Rexception);
+ __ load_const_optimized(R11_scratch1, Interpreter::throw_exception_entry(), R12_scratch2);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_continuation_for(TosState state) {
+ address entry = __ pc();
+ __ unimplemented("generate_continuation_for");
+ return entry;
+}
+
+// This entry is returned to when a call returns to the interpreter.
+// When we arrive here, we expect that the callee stack frame is already popped.
+address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) {
+ address entry = __ pc();
+
+ // Move the value out of the return register back to the TOS cache of current frame.
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R17_tos, R3_RET); break; // RET -> TOS cache
+ case ftos:
+ case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
+ case vtos: break; // Nothing to do, this was a void return.
+ default : ShouldNotReachHere();
+ }
+
+ __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+
+ // Compiled code destroys templateTableBase, reload.
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R12_scratch2);
+
+ const Register cache = R11_scratch1;
+ const Register size = R12_scratch2;
+ __ get_cache_and_index_at_bcp(cache, 1, index_size);
+
+ // Big Endian (get least significant byte of 64 bit value):
+ __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache);
+ __ sldi(size, size, Interpreter::logStackElementSize);
+ __ add(R15_esp, R15_esp, size);
+ __ dispatch_next(state, step);
+ return entry;
+}
+
+address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) {
+ address entry = __ pc();
+ // If state != vtos, we're returning from a native method, which put it's result
+ // into the result register. So move the value out of the return register back
+ // to the TOS cache of current frame.
+
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R17_tos, R3_RET); break; // GR_RET -> TOS cache
+ case ftos:
+ case dtos: __ fmr(F15_ftos, F1_RET); break; // TOS cache -> GR_FRET
+ case vtos: break; // Nothing to do, this was a void return.
+ default : ShouldNotReachHere();
+ }
+
+ // Load LcpoolCache @@@ should be already set!
+ __ get_constant_pool_cache(R27_constPoolCache);
+
+ // Handle a pending exception, fall through if none.
+ __ check_and_forward_exception(R11_scratch1, R12_scratch2);
+
+ // Start executing bytecodes.
+ __ dispatch_next(state, step);
+
+ return entry;
+}
+
+// A result handler converts the native result into java format.
+// Use the shared code between c++ and template interpreter.
+address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) {
+ return AbstractInterpreterGenerator::generate_result_handler_for(type);
+}
+
+address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) {
+ address entry = __ pc();
+
+ __ push(state);
+ __ call_VM(noreg, runtime_entry);
+ __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos));
+
+ return entry;
+}
+
+// Helpers for commoning out cases in the various type of method entries.
+
+// Increment invocation count & check for overflow.
+//
+// Note: checking for negative value instead of overflow
+// so we have a 'sticky' overflow test.
+//
+void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
+ // Note: In tiered we increment either counters in method or in MDO depending if we're profiling or not.
+ Register Rscratch1 = R11_scratch1;
+ Register Rscratch2 = R12_scratch2;
+ Register R3_counters = R3_ARG1;
+ Label done;
+
+ if (TieredCompilation) {
+ const int increment = InvocationCounter::count_increment;
+ const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
+ Label no_mdo;
+ if (ProfileInterpreter) {
+ const Register Rmdo = Rscratch1;
+ // If no method data exists, go to profile_continue.
+ __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
+ __ cmpdi(CCR0, Rmdo, 0);
+ __ beq(CCR0, no_mdo);
+
+ // Increment backedge counter in the MDO.
+ const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mdo_bc_offs, Rmdo);
+ __ load_const_optimized(Rscratch1, mask, R0);
+ __ and_(Rscratch1, Rscratch2, Rscratch1);
+ __ bne(CCR0, done);
+ __ b(*overflow);
+ }
+
+ // Increment counter in MethodCounters*.
+ const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ bind(no_mdo);
+ __ get_method_counters(R19_method, R3_counters, done);
+ __ lwz(Rscratch2, mo_bc_offs, R3_counters);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mo_bc_offs, R3_counters);
+ __ load_const_optimized(Rscratch1, mask, R0);
+ __ and_(Rscratch1, Rscratch2, Rscratch1);
+ __ beq(CCR0, *overflow);
+
+ __ bind(done);
+
+ } else {
+
+ // Update standard invocation counters.
+ Register Rsum_ivc_bec = R4_ARG2;
+ __ get_method_counters(R19_method, R3_counters, done);
+ __ increment_invocation_counter(R3_counters, Rsum_ivc_bec, R12_scratch2);
+ // Increment interpreter invocation counter.
+ if (ProfileInterpreter) { // %%% Merge this into methodDataOop.
+ __ lwz(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, in_bytes(MethodCounters::interpreter_invocation_counter_offset()), R3_counters);
+ }
+ // Check if we must create a method data obj.
+ if (ProfileInterpreter && profile_method != NULL) {
+ const Register profile_limit = Rscratch1;
+ int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true);
+ __ lwz(profile_limit, pl_offs, profile_limit);
+ // Test to see if we should create a method data oop.
+ __ cmpw(CCR0, Rsum_ivc_bec, profile_limit);
+ __ blt(CCR0, *profile_method_continue);
+ // If no method data exists, go to profile_method.
+ __ test_method_data_pointer(*profile_method);
+ }
+ // Finally check for counter overflow.
+ if (overflow) {
+ const Register invocation_limit = Rscratch1;
+ int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true);
+ __ lwz(invocation_limit, il_offs, invocation_limit);
+ assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size");
+ __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit);
+ __ bge(CCR0, *overflow);
+ }
+
+ __ bind(done);
+ }
+}
+
+// Generate code to initiate compilation on invocation counter overflow.
+void TemplateInterpreterGenerator::generate_counter_overflow(Label& continue_entry) {
+ // Generate code to initiate compilation on the counter overflow.
+
+ // InterpreterRuntime::frequency_counter_overflow takes one arguments,
+ // which indicates if the counter overflow occurs at a backwards branch (NULL bcp)
+ // We pass zero in.
+ // The call returns the address of the verified entry point for the method or NULL
+ // if the compilation did not complete (either went background or bailed out).
+ //
+ // Unlike the C++ interpreter above: Check exceptions!
+ // Assumption: Caller must set the flag "do_not_unlock_if_sychronized" if the monitor of a sync'ed
+ // method has not yet been created. Thus, no unlocking of a non-existing monitor can occur.
+
+ __ li(R4_ARG2, 0);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true);
+
+ // Returns verified_entry_point or NULL.
+ // We ignore it in any case.
+ __ b(continue_entry);
+}
+
+void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_frame_size, Register Rscratch1) {
+ assert_different_registers(Rmem_frame_size, Rscratch1);
+ __ generate_stack_overflow_check_with_compare_and_throw(Rmem_frame_size, Rscratch1);
+}
+
+void TemplateInterpreterGenerator::unlock_method(bool check_exceptions) {
+ __ unlock_object(R26_monitor, check_exceptions);
+}
+
+// Lock the current method, interpreter register window must be set up!
+void TemplateInterpreterGenerator::lock_method(Register Rflags, Register Rscratch1, Register Rscratch2, bool flags_preloaded) {
+ const Register Robj_to_lock = Rscratch2;
+
+ {
+ if (!flags_preloaded) {
+ __ lwz(Rflags, method_(access_flags));
+ }
+
+#ifdef ASSERT
+ // Check if methods needs synchronization.
+ {
+ Label Lok;
+ __ testbitdi(CCR0, R0, Rflags, JVM_ACC_SYNCHRONIZED_BIT);
+ __ btrue(CCR0,Lok);
+ __ stop("method doesn't need synchronization");
+ __ bind(Lok);
+ }
+#endif // ASSERT
+ }
+
+ // Get synchronization object to Rscratch2.
+ {
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+ Label Lstatic;
+ Label Ldone;
+
+ __ testbitdi(CCR0, R0, Rflags, JVM_ACC_STATIC_BIT);
+ __ btrue(CCR0, Lstatic);
+
+ // Non-static case: load receiver obj from stack and we're done.
+ __ ld(Robj_to_lock, R18_locals);
+ __ b(Ldone);
+
+ __ bind(Lstatic); // Static case: Lock the java mirror
+ __ ld(Robj_to_lock, in_bytes(Method::const_offset()), R19_method);
+ __ ld(Robj_to_lock, in_bytes(ConstMethod::constants_offset()), Robj_to_lock);
+ __ ld(Robj_to_lock, ConstantPool::pool_holder_offset_in_bytes(), Robj_to_lock);
+ __ ld(Robj_to_lock, mirror_offset, Robj_to_lock);
+
+ __ bind(Ldone);
+ __ verify_oop(Robj_to_lock);
+ }
+
+ // Got the oop to lock => execute!
+ __ add_monitor_to_stack(true, Rscratch1, R0);
+
+ __ std(Robj_to_lock, BasicObjectLock::obj_offset_in_bytes(), R26_monitor);
+ __ lock_object(R26_monitor, Robj_to_lock);
+}
+
+// Generate a fixed interpreter frame for pure interpreter
+// and I2N native transition frames.
+//
+// Before (stack grows downwards):
+//
+// | ... |
+// |------------- |
+// | java arg0 |
+// | ... |
+// | java argn |
+// | | <- R15_esp
+// | |
+// |--------------|
+// | abi_112 |
+// | | <- R1_SP
+// |==============|
+//
+//
+// After:
+//
+// | ... |
+// | java arg0 |<- R18_locals
+// | ... |
+// | java argn |
+// |--------------|
+// | |
+// | java locals |
+// | |
+// |--------------|
+// | abi_48 |
+// |==============|
+// | |
+// | istate |
+// | |
+// |--------------|
+// | monitor |<- R26_monitor
+// |--------------|
+// | |<- R15_esp
+// | expression |
+// | stack |
+// | |
+// |--------------|
+// | |
+// | abi_112 |<- R1_SP
+// |==============|
+//
+// The top most frame needs an abi space of 112 bytes. This space is needed,
+// since we call to c. The c function may spill their arguments to the caller
+// frame. When we call to java, we don't need these spill slots. In order to save
+// space on the stack, we resize the caller. However, java local reside in
+// the caller frame and the frame has to be increased. The frame_size for the
+// current frame was calculated based on max_stack as size for the expression
+// stack. At the call, just a part of the expression stack might be used.
+// We don't want to waste this space and cut the frame back accordingly.
+// The resulting amount for resizing is calculated as follows:
+// resize = (number_of_locals - number_of_arguments) * slot_size
+// + (R1_SP - R15_esp) + 48
+//
+// The size for the callee frame is calculated:
+// framesize = 112 + max_stack + monitor + state_size
+//
+// maxstack: Max number of slots on the expression stack, loaded from the method.
+// monitor: We statically reserve room for one monitor object.
+// state_size: We save the current state of the interpreter to this area.
+//
+void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call, Register Rsize_of_parameters, Register Rsize_of_locals) {
+ Register parent_frame_resize = R6_ARG4, // Frame will grow by this number of bytes.
+ top_frame_size = R7_ARG5,
+ Rconst_method = R8_ARG6;
+
+ assert_different_registers(Rsize_of_parameters, Rsize_of_locals, parent_frame_resize, top_frame_size);
+
+ __ ld(Rconst_method, method_(const));
+ __ lhz(Rsize_of_parameters /* number of params */,
+ in_bytes(ConstMethod::size_of_parameters_offset()), Rconst_method);
+ if (native_call) {
+ // If we're calling a native method, we reserve space for the worst-case signature
+ // handler varargs vector, which is max(Argument::n_register_parameters, parameter_count+2).
+ // We add two slots to the parameter_count, one for the jni
+ // environment and one for a possible native mirror.
+ Label skip_native_calculate_max_stack;
+ __ addi(top_frame_size, Rsize_of_parameters, 2);
+ __ cmpwi(CCR0, top_frame_size, Argument::n_register_parameters);
+ __ bge(CCR0, skip_native_calculate_max_stack);
+ __ li(top_frame_size, Argument::n_register_parameters);
+ __ bind(skip_native_calculate_max_stack);
+ __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
+ __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
+ __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
+ assert(Rsize_of_locals == noreg, "Rsize_of_locals not initialized"); // Only relevant value is Rsize_of_parameters.
+ } else {
+ __ lhz(Rsize_of_locals /* number of params */, in_bytes(ConstMethod::size_of_locals_offset()), Rconst_method);
+ __ sldi(Rsize_of_parameters, Rsize_of_parameters, Interpreter::logStackElementSize);
+ __ sldi(Rsize_of_locals, Rsize_of_locals, Interpreter::logStackElementSize);
+ __ lhz(top_frame_size, in_bytes(ConstMethod::max_stack_offset()), Rconst_method);
+ __ sub(R11_scratch1, Rsize_of_locals, Rsize_of_parameters); // >=0
+ __ sub(parent_frame_resize, R1_SP, R15_esp); // <0, off by Interpreter::stackElementSize!
+ __ sldi(top_frame_size, top_frame_size, Interpreter::logStackElementSize);
+ __ add(parent_frame_resize, parent_frame_resize, R11_scratch1);
+ }
+
+ // Compute top frame size.
+ __ addi(top_frame_size, top_frame_size, frame::abi_reg_args_size + frame::ijava_state_size);
+
+ // Cut back area between esp and max_stack.
+ __ addi(parent_frame_resize, parent_frame_resize, frame::abi_minframe_size - Interpreter::stackElementSize);
+
+ __ round_to(top_frame_size, frame::alignment_in_bytes);
+ __ round_to(parent_frame_resize, frame::alignment_in_bytes);
+ // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size.
+ // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48.
+
+ {
+ // --------------------------------------------------------------------------
+ // Stack overflow check
+
+ Label cont;
+ __ add(R11_scratch1, parent_frame_resize, top_frame_size);
+ generate_stack_overflow_check(R11_scratch1, R12_scratch2);
+ }
+
+ // Set up interpreter state registers.
+
+ __ add(R18_locals, R15_esp, Rsize_of_parameters);
+ __ ld(R27_constPoolCache, in_bytes(ConstMethod::constants_offset()), Rconst_method);
+ __ ld(R27_constPoolCache, ConstantPool::cache_offset_in_bytes(), R27_constPoolCache);
+
+ // Set method data pointer.
+ if (ProfileInterpreter) {
+ Label zero_continue;
+ __ ld(R28_mdx, method_(method_data));
+ __ cmpdi(CCR0, R28_mdx, 0);
+ __ beq(CCR0, zero_continue);
+ __ addi(R28_mdx, R28_mdx, in_bytes(MethodData::data_offset()));
+ __ bind(zero_continue);
+ }
+
+ if (native_call) {
+ __ li(R14_bcp, 0); // Must initialize.
+ } else {
+ __ add(R14_bcp, in_bytes(ConstMethod::codes_offset()), Rconst_method);
+ }
+
+ // Resize parent frame.
+ __ mflr(R12_scratch2);
+ __ neg(parent_frame_resize, parent_frame_resize);
+ __ resize_frame(parent_frame_resize, R11_scratch1);
+ __ std(R12_scratch2, _abi(lr), R1_SP);
+
+ __ addi(R26_monitor, R1_SP, - frame::ijava_state_size);
+ __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize);
+
+ // Store values.
+ // R15_esp, R14_bcp, R26_monitor, R28_mdx are saved at java calls
+ // in InterpreterMacroAssembler::call_from_interpreter.
+ __ std(R19_method, _ijava_state_neg(method), R1_SP);
+ __ std(R21_sender_SP, _ijava_state_neg(sender_sp), R1_SP);
+ __ std(R27_constPoolCache, _ijava_state_neg(cpoolCache), R1_SP);
+ __ std(R18_locals, _ijava_state_neg(locals), R1_SP);
+
+ // Note: esp, bcp, monitor, mdx live in registers. Hence, the correct version can only
+ // be found in the frame after save_interpreter_state is done. This is always true
+ // for non-top frames. But when a signal occurs, dumping the top frame can go wrong,
+ // because e.g. frame::interpreter_frame_bcp() will not access the correct value
+ // (Enhanced Stack Trace).
+ // The signal handler does not save the interpreter state into the frame.
+ __ li(R0, 0);
+#ifdef ASSERT
+ // Fill remaining slots with constants.
+ __ load_const_optimized(R11_scratch1, 0x5afe);
+ __ load_const_optimized(R12_scratch2, 0xdead);
+#endif
+ // We have to initialize some frame slots for native calls (accessed by GC).
+ if (native_call) {
+ __ std(R26_monitor, _ijava_state_neg(monitors), R1_SP);
+ __ std(R14_bcp, _ijava_state_neg(bcp), R1_SP);
+ if (ProfileInterpreter) { __ std(R28_mdx, _ijava_state_neg(mdx), R1_SP); }
+ }
+#ifdef ASSERT
+ else {
+ __ std(R12_scratch2, _ijava_state_neg(monitors), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(bcp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(mdx), R1_SP);
+ }
+ __ std(R11_scratch1, _ijava_state_neg(ijava_reserved), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(esp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(lresult), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(fresult), R1_SP);
+#endif
+ __ subf(R12_scratch2, top_frame_size, R1_SP);
+ __ std(R0, _ijava_state_neg(oop_tmp), R1_SP);
+ __ std(R12_scratch2, _ijava_state_neg(top_frame_sp), R1_SP);
+
+ // Push top frame.
+ __ push_frame(top_frame_size, R11_scratch1);
+}
+
+// End of helpers
+
+// ============================================================================
+// Various method entries
+//
+
+// Empty method, generate a very fast return. We must skip this entry if
+// someone's debugging, indicated by the flag
+// "interp_mode" in the Thread obj.
+// Note: empty methods are generated mostly methods that do assertions, which are
+// disabled in the "java opt build".
+address TemplateInterpreterGenerator::generate_empty_entry(void) {
+ if (!UseFastEmptyMethods) {
+ NOT_PRODUCT(__ should_not_reach_here();)
+ return Interpreter::entry_for_kind(Interpreter::zerolocals);
+ }
+
+ Label Lslow_path;
+ const Register Rjvmti_mode = R11_scratch1;
+ address entry = __ pc();
+
+ __ lwz(Rjvmti_mode, thread_(interp_only_mode));
+ __ cmpwi(CCR0, Rjvmti_mode, 0);
+ __ bne(CCR0, Lslow_path); // jvmti_mode!=0
+
+ // Noone's debuggin: Simply return.
+ // Pop c2i arguments (if any) off when we return.
+#ifdef ASSERT
+ __ ld(R9_ARG7, 0, R1_SP);
+ __ ld(R10_ARG8, 0, R21_sender_SP);
+ __ cmpd(CCR0, R9_ARG7, R10_ARG8);
+ __ asm_assert_eq("backlink", 0x545);
+#endif // ASSERT
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+
+ // And we're done.
+ __ blr();
+
+ __ bind(Lslow_path);
+ __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1);
+ __ flush();
+
+ return entry;
+}
+
+// Support abs and sqrt like in compiler.
+// For others we can use a normal (native) entry.
+
+inline bool math_entry_available(AbstractInterpreter::MethodKind kind) {
+ // Provide math entry with debugging on demand.
+ // Note: Debugging changes which code will get executed:
+ // Debugging or disabled InlineIntrinsics: java method will get interpreted and performs a native call.
+ // Not debugging and enabled InlineIntrinics: processor instruction will get used.
+ // Result might differ slightly due to rounding etc.
+ if (!InlineIntrinsics && (!FLAG_IS_ERGO(InlineIntrinsics))) return false; // Generate a vanilla entry.
+
+ return ((kind==Interpreter::java_lang_math_sqrt && VM_Version::has_fsqrt()) ||
+ (kind==Interpreter::java_lang_math_abs));
+}
+
+address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) {
+ if (!math_entry_available(kind)) {
+ NOT_PRODUCT(__ should_not_reach_here();)
+ return Interpreter::entry_for_kind(Interpreter::zerolocals);
+ }
+
+ Label Lslow_path;
+ const Register Rjvmti_mode = R11_scratch1;
+ address entry = __ pc();
+
+ // Provide math entry with debugging on demand.
+ __ lwz(Rjvmti_mode, thread_(interp_only_mode));
+ __ cmpwi(CCR0, Rjvmti_mode, 0);
+ __ bne(CCR0, Lslow_path); // jvmti_mode!=0
+
+ __ lfd(F1_RET, Interpreter::stackElementSize, R15_esp);
+
+ // Pop c2i arguments (if any) off when we return.
+#ifdef ASSERT
+ __ ld(R9_ARG7, 0, R1_SP);
+ __ ld(R10_ARG8, 0, R21_sender_SP);
+ __ cmpd(CCR0, R9_ARG7, R10_ARG8);
+ __ asm_assert_eq("backlink", 0x545);
+#endif // ASSERT
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+
+ if (kind == Interpreter::java_lang_math_sqrt) {
+ __ fsqrt(F1_RET, F1_RET);
+ } else if (kind == Interpreter::java_lang_math_abs) {
+ __ fabs(F1_RET, F1_RET);
+ } else {
+ ShouldNotReachHere();
+ }
+
+ // And we're done.
+ __ blr();
+
+ // Provide slow path for JVMTI case.
+ __ bind(Lslow_path);
+ __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R12_scratch2);
+ __ flush();
+
+ return entry;
+}
+
+// Interpreter stub for calling a native method. (asm interpreter)
+// This sets up a somewhat different looking stack for calling the
+// native method than the typical interpreter frame setup.
+//
+// On entry:
+// R19_method - method
+// R16_thread - JavaThread*
+// R15_esp - intptr_t* sender tos
+//
+// abstract stack (grows up)
+// [ IJava (caller of JNI callee) ] <-- ASP
+// ...
+address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
+
+ address entry = __ pc();
+
+ const bool inc_counter = UseCompiler || CountCompiledCalls;
+
+ // -----------------------------------------------------------------------------
+ // Allocate a new frame that represents the native callee (i2n frame).
+ // This is not a full-blown interpreter frame, but in particular, the
+ // following registers are valid after this:
+ // - R19_method
+ // - R18_local (points to start of argumuments to native function)
+ //
+ // abstract stack (grows up)
+ // [ IJava (caller of JNI callee) ] <-- ASP
+ // ...
+
+ const Register signature_handler_fd = R11_scratch1;
+ const Register pending_exception = R0;
+ const Register result_handler_addr = R31;
+ const Register native_method_fd = R11_scratch1;
+ const Register access_flags = R22_tmp2;
+ const Register active_handles = R11_scratch1; // R26_monitor saved to state.
+ const Register sync_state = R12_scratch2;
+ const Register sync_state_addr = sync_state; // Address is dead after use.
+ const Register suspend_flags = R11_scratch1;
+
+ //=============================================================================
+ // Allocate new frame and initialize interpreter state.
+
+ Label exception_return;
+ Label exception_return_sync_check;
+ Label stack_overflow_return;
+
+ // Generate new interpreter state and jump to stack_overflow_return in case of
+ // a stack overflow.
+ //generate_compute_interpreter_state(stack_overflow_return);
+
+ Register size_of_parameters = R22_tmp2;
+
+ generate_fixed_frame(true, size_of_parameters, noreg /* unused */);
+
+ //=============================================================================
+ // Increment invocation counter. On overflow, entry to JNI method
+ // will be compiled.
+ Label invocation_counter_overflow, continue_after_compile;
+ if (inc_counter) {
+ if (synchronized) {
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ // This flag has two effects, one is to force an unwind in the topmost
+ // interpreter frame and not perform an unlock while doing so.
+ __ li(R0, 1);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
+
+ __ BIND(continue_after_compile);
+ // Reset the _do_not_unlock_if_synchronized flag.
+ if (synchronized) {
+ __ li(R0, 0);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ }
+
+ // access_flags = method->access_flags();
+ // Load access flags.
+ assert(access_flags->is_nonvolatile(),
+ "access_flags must be in a non-volatile register");
+ // Type check.
+ assert(4 == sizeof(AccessFlags), "unexpected field size");
+ __ lwz(access_flags, method_(access_flags));
+
+ // We don't want to reload R19_method and access_flags after calls
+ // to some helper functions.
+ assert(R19_method->is_nonvolatile(),
+ "R19_method must be a non-volatile register");
+
+ // Check for synchronized methods. Must happen AFTER invocation counter
+ // check, so method is not locked if counter overflows.
+
+ if (synchronized) {
+ lock_method(access_flags, R11_scratch1, R12_scratch2, true);
+
+ // Update monitor in state.
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R26_monitor, _ijava_state_neg(monitors), R11_scratch1);
+ }
+
+ // jvmti/jvmpi support
+ __ notify_method_entry();
+
+ //=============================================================================
+ // Get and call the signature handler.
+
+ __ ld(signature_handler_fd, method_(signature_handler));
+ Label call_signature_handler;
+
+ __ cmpdi(CCR0, signature_handler_fd, 0);
+ __ bne(CCR0, call_signature_handler);
+
+ // Method has never been called. Either generate a specialized
+ // handler or point to the slow one.
+ //
+ // Pass parameter 'false' to avoid exception check in call_VM.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false);
+
+ // Check for an exception while looking up the target method. If we
+ // incurred one, bail.
+ __ ld(pending_exception, thread_(pending_exception));
+ __ cmpdi(CCR0, pending_exception, 0);
+ __ bne(CCR0, exception_return_sync_check); // Has pending exception.
+
+ // Reload signature handler, it may have been created/assigned in the meanwhile.
+ __ ld(signature_handler_fd, method_(signature_handler));
+ __ twi_0(signature_handler_fd); // Order wrt. load of klass mirror and entry point (isync is below).
+
+ __ BIND(call_signature_handler);
+
+ // Before we call the signature handler we push a new frame to
+ // protect the interpreter frame volatile registers when we return
+ // from jni but before we can get back to Java.
+
+ // First set the frame anchor while the SP/FP registers are
+ // convenient and the slow signature handler can use this same frame
+ // anchor.
+
+ // We have a TOP_IJAVA_FRAME here, which belongs to us.
+ __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/);
+
+ // Now the interpreter frame (and its call chain) have been
+ // invalidated and flushed. We are now protected against eager
+ // being enabled in native code. Even if it goes eager the
+ // registers will be reloaded as clean and we will invalidate after
+ // the call so no spurious flush should be possible.
+
+ // Call signature handler and pass locals address.
+ //
+ // Our signature handlers copy required arguments to the C stack
+ // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13.
+ __ mr(R3_ARG1, R18_locals);
+ __ ld(signature_handler_fd, 0, signature_handler_fd);
+
+ __ call_stub(signature_handler_fd);
+
+ // Remove the register parameter varargs slots we allocated in
+ // compute_interpreter_state. SP+16 ends up pointing to the ABI
+ // outgoing argument area.
+ //
+ // Not needed on PPC64.
+ //__ add(SP, SP, Argument::n_register_parameters*BytesPerWord);
+
+ assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register");
+ // Save across call to native method.
+ __ mr(result_handler_addr, R3_RET);
+
+ __ isync(); // Acquire signature handler before trying to fetch the native entry point and klass mirror.
+
+ // Set up fixed parameters and call the native method.
+ // If the method is static, get mirror into R4_ARG2.
+ {
+ Label method_is_not_static;
+ // Access_flags is non-volatile and still, no need to restore it.
+
+ // Restore access flags.
+ __ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT);
+ __ bfalse(CCR0, method_is_not_static);
+
+ // constants = method->constants();
+ __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
+ __ ld(R11_scratch1, in_bytes(ConstMethod::constants_offset()), R11_scratch1);
+ // pool_holder = method->constants()->pool_holder();
+ __ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(),
+ R11_scratch1/*constants*/);
+
+ const int mirror_offset = in_bytes(Klass::java_mirror_offset());
+
+ // mirror = pool_holder->klass_part()->java_mirror();
+ __ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/);
+ // state->_native_mirror = mirror;
+
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1);
+ // R4_ARG2 = &state->_oop_temp;
+ __ addi(R4_ARG2, R11_scratch1, _ijava_state_neg(oop_tmp));
+ __ BIND(method_is_not_static);
+ }
+
+ // At this point, arguments have been copied off the stack into
+ // their JNI positions. Oops are boxed in-place on the stack, with
+ // handles copied to arguments. The result handler address is in a
+ // register.
+
+ // Pass JNIEnv address as first parameter.
+ __ addir(R3_ARG1, thread_(jni_environment));
+
+ // Load the native_method entry before we change the thread state.
+ __ ld(native_method_fd, method_(native_function));
+
+ //=============================================================================
+ // Transition from _thread_in_Java to _thread_in_native. As soon as
+ // we make this change the safepoint code needs to be certain that
+ // the last Java frame we established is good. The pc in that frame
+ // just needs to be near here not an actual return address.
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0, _thread_in_native);
+ __ release();
+
+ // TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
+ __ stw(R0, thread_(thread_state));
+
+ if (UseMembar) {
+ __ fence();
+ }
+
+ //=============================================================================
+ // Call the native method. Argument registers must not have been
+ // overwritten since "__ call_stub(signature_handler);" (except for
+ // ARG1 and ARG2 for static methods).
+ __ call_c(native_method_fd);
+
+ __ li(R0, 0);
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ std(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
+ __ stfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
+ __ std(R0/*mirror*/, _ijava_state_neg(oop_tmp), R11_scratch1); // reset
+
+ // Note: C++ interpreter needs the following here:
+ // The frame_manager_lr field, which we use for setting the last
+ // java frame, gets overwritten by the signature handler. Restore
+ // it now.
+ //__ get_PC_trash_LR(R11_scratch1);
+ //__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
+
+ // Because of GC R19_method may no longer be valid.
+
+ // Block, if necessary, before resuming in _thread_in_Java state.
+ // In order for GC to work, don't clear the last_Java_sp until after
+ // blocking.
+
+ //=============================================================================
+ // Switch thread to "native transition" state before reading the
+ // synchronization state. This additional state is necessary
+ // because reading and testing the synchronization state is not
+ // atomic w.r.t. GC, as this scenario demonstrates: Java thread A,
+ // in _thread_in_native state, loads _not_synchronized and is
+ // preempted. VM thread changes sync state to synchronizing and
+ // suspends threads for GC. Thread A is resumed to finish this
+ // native method, but doesn't block here since it didn't see any
+ // synchronization in progress, and escapes.
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0/*thread_state*/, _thread_in_native_trans);
+ __ release();
+ __ stw(R0/*thread_state*/, thread_(thread_state));
+ if (UseMembar) {
+ __ fence();
+ }
+ // Write serialization page so that the VM thread can do a pseudo remote
+ // membar. We use the current thread pointer to calculate a thread
+ // specific offset to write to within the page. This minimizes bus
+ // traffic due to cache line collision.
+ else {
+ __ serialize_memory(R16_thread, R11_scratch1, R12_scratch2);
+ }
+
+ // Now before we return to java we must look for a current safepoint
+ // (a new safepoint can not start since we entered native_trans).
+ // We must check here because a current safepoint could be modifying
+ // the callers registers right this moment.
+
+ // Acquire isn't strictly necessary here because of the fence, but
+ // sync_state is declared to be volatile, so we do it anyway
+ // (cmp-br-isync on one path, release (same as acquire on PPC64) on the other path).
+ int sync_state_offs = __ load_const_optimized(sync_state_addr, SafepointSynchronize::address_of_state(), /*temp*/R0, true);
+
+ // TODO PPC port assert(4 == SafepointSynchronize::sz_state(), "unexpected field size");
+ __ lwz(sync_state, sync_state_offs, sync_state_addr);
+
+ // TODO PPC port assert(4 == Thread::sz_suspend_flags(), "unexpected field size");
+ __ lwz(suspend_flags, thread_(suspend_flags));
+
+ Label sync_check_done;
+ Label do_safepoint;
+ // No synchronization in progress nor yet synchronized.
+ __ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
+ // Not suspended.
+ __ cmpwi(CCR1, suspend_flags, 0);
+
+ __ bne(CCR0, do_safepoint);
+ __ beq(CCR1, sync_check_done);
+ __ bind(do_safepoint);
+ __ isync();
+ // Block. We do the call directly and leave the current
+ // last_Java_frame setup undisturbed. We must save any possible
+ // native result across the call. No oop is present.
+
+ __ mr(R3_ARG1, R16_thread);
+ __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
+ relocInfo::none);
+
+ __ bind(sync_check_done);
+
+ //=============================================================================
+ // <<<<<< Back in Interpreter Frame >>>>>
+
+ // We are in thread_in_native_trans here and back in the normal
+ // interpreter frame. We don't have to do anything special about
+ // safepoints and we can switch to Java mode anytime we are ready.
+
+ // Note: frame::interpreter_frame_result has a dependency on how the
+ // method result is saved across the call to post_method_exit. For
+ // native methods it assumes that the non-FPU/non-void result is
+ // saved in _native_lresult and a FPU result in _native_fresult. If
+ // this changes then the interpreter_frame_result implementation
+ // will need to be updated too.
+
+ // On PPC64, we have stored the result directly after the native call.
+
+ //=============================================================================
+ // Back in Java
+
+ // We use release_store_fence to update values like the thread state, where
+ // we don't want the current thread to continue until all our prior memory
+ // accesses (including the new thread state) are visible to other threads.
+ __ li(R0/*thread_state*/, _thread_in_Java);
+ __ release();
+ __ stw(R0/*thread_state*/, thread_(thread_state));
+ if (UseMembar) {
+ __ fence();
+ }
+
+ __ reset_last_Java_frame();
+
+ // Jvmdi/jvmpi support. Whether we've got an exception pending or
+ // not, and whether unlocking throws an exception or not, we notify
+ // on native method exit. If we do have an exception, we'll end up
+ // in the caller's context to handle it, so if we don't do the
+ // notify here, we'll drop it on the floor.
+ __ notify_method_exit(true/*native method*/,
+ ilgl /*illegal state (not used for native methods)*/,
+ InterpreterMacroAssembler::NotifyJVMTI,
+ false /*check_exceptions*/);
+
+ //=============================================================================
+ // Handle exceptions
+
+ if (synchronized) {
+ // Don't check for exceptions since we're still in the i2n frame. Do that
+ // manually afterwards.
+ unlock_method(false);
+ }
+
+ // Reset active handles after returning from native.
+ // thread->active_handles()->clear();
+ __ ld(active_handles, thread_(active_handles));
+ // TODO PPC port assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size");
+ __ li(R0, 0);
+ __ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles);
+
+ Label exception_return_sync_check_already_unlocked;
+ __ ld(R0/*pending_exception*/, thread_(pending_exception));
+ __ cmpdi(CCR0, R0/*pending_exception*/, 0);
+ __ bne(CCR0, exception_return_sync_check_already_unlocked);
+
+ //-----------------------------------------------------------------------------
+ // No exception pending.
+
+ // Move native method result back into proper registers and return.
+ // Invoke result handler (may unbox/promote).
+ __ ld(R11_scratch1, 0, R1_SP);
+ __ ld(R3_RET, _ijava_state_neg(lresult), R11_scratch1);
+ __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1);
+ __ call_stub(result_handler_addr);
+
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
+
+ // Must use the return pc which was loaded from the caller's frame
+ // as the VM uses return-pc-patching for deoptimization.
+ __ mtlr(R0);
+ __ blr();
+
+ //-----------------------------------------------------------------------------
+ // An exception is pending. We call into the runtime only if the
+ // caller was not interpreted. If it was interpreted the
+ // interpreter will do the correct thing. If it isn't interpreted
+ // (call stub/compiled code) we will change our return and continue.
+
+ __ BIND(exception_return_sync_check);
+
+ if (synchronized) {
+ // Don't check for exceptions since we're still in the i2n frame. Do that
+ // manually afterwards.
+ unlock_method(false);
+ }
+ __ BIND(exception_return_sync_check_already_unlocked);
+
+ const Register return_pc = R31;
+
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+
+ // Get the address of the exception handler.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
+ R16_thread,
+ return_pc /* return pc */);
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, noreg, R11_scratch1, R12_scratch2);
+
+ // Load the PC of the the exception handler into LR.
+ __ mtlr(R3_RET);
+
+ // Load exception into R3_ARG1 and clear pending exception in thread.
+ __ ld(R3_ARG1/*exception*/, thread_(pending_exception));
+ __ li(R4_ARG2, 0);
+ __ std(R4_ARG2, thread_(pending_exception));
+
+ // Load the original return pc into R4_ARG2.
+ __ mr(R4_ARG2/*issuing_pc*/, return_pc);
+
+ // Return to exception handler.
+ __ blr();
+
+ //=============================================================================
+ // Counter overflow.
+
+ if (inc_counter) {
+ // Handle invocation counter overflow.
+ __ bind(invocation_counter_overflow);
+
+ generate_counter_overflow(continue_after_compile);
+ }
+
+ return entry;
+}
+
+// Generic interpreted method entry to (asm) interpreter.
+//
+address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
+ bool inc_counter = UseCompiler || CountCompiledCalls;
+ address entry = __ pc();
+ // Generate the code to allocate the interpreter stack frame.
+ Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame.
+ Rsize_of_locals = R5_ARG3; // Written by generate_fixed_frame.
+
+ generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals);
+
+#ifdef FAST_DISPATCH
+ __ unimplemented("Fast dispatch in generate_normal_entry");
+#if 0
+ __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables);
+ // Set bytecode dispatch table base.
+#endif
+#endif
+
+ // --------------------------------------------------------------------------
+ // Zero out non-parameter locals.
+ // Note: *Always* zero out non-parameter locals as Sparc does. It's not
+ // worth to ask the flag, just do it.
+ Register Rslot_addr = R6_ARG4,
+ Rnum = R7_ARG5;
+ Label Lno_locals, Lzero_loop;
+
+ // Set up the zeroing loop.
+ __ subf(Rnum, Rsize_of_parameters, Rsize_of_locals);
+ __ subf(Rslot_addr, Rsize_of_parameters, R18_locals);
+ __ srdi_(Rnum, Rnum, Interpreter::logStackElementSize);
+ __ beq(CCR0, Lno_locals);
+ __ li(R0, 0);
+ __ mtctr(Rnum);
+
+ // The zero locals loop.
+ __ bind(Lzero_loop);
+ __ std(R0, 0, Rslot_addr);
+ __ addi(Rslot_addr, Rslot_addr, -Interpreter::stackElementSize);
+ __ bdnz(Lzero_loop);
+
+ __ bind(Lno_locals);
+
+ // --------------------------------------------------------------------------
+ // Counter increment and overflow check.
+ Label invocation_counter_overflow,
+ profile_method,
+ profile_method_continue;
+ if (inc_counter || ProfileInterpreter) {
+
+ Register Rdo_not_unlock_if_synchronized_addr = R11_scratch1;
+ if (synchronized) {
+ // Since at this point in the method invocation the exception handler
+ // would try to exit the monitor of synchronized methods which hasn't
+ // been entered yet, we set the thread local variable
+ // _do_not_unlock_if_synchronized to true. If any exception was thrown by
+ // runtime, exception handling i.e. unlock_if_synchronized_method will
+ // check this thread local flag.
+ // This flag has two effects, one is to force an unwind in the topmost
+ // interpreter frame and not perform an unlock while doing so.
+ __ li(R0, 1);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ // Increment invocation counter and check for overflow.
+ if (inc_counter) {
+ generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue);
+ }
+
+ __ bind(profile_method_continue);
+
+ // Reset the _do_not_unlock_if_synchronized flag.
+ if (synchronized) {
+ __ li(R0, 0);
+ __ stb(R0, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()), R16_thread);
+ }
+ }
+
+ // --------------------------------------------------------------------------
+ // Locking of synchronized methods. Must happen AFTER invocation_counter
+ // check and stack overflow check, so method is not locked if overflows.
+ if (synchronized) {
+ lock_method(R3_ARG1, R4_ARG2, R5_ARG3);
+ }
+#ifdef ASSERT
+ else {
+ Label Lok;
+ __ lwz(R0, in_bytes(Method::access_flags_offset()), R19_method);
+ __ andi_(R0, R0, JVM_ACC_SYNCHRONIZED);
+ __ asm_assert_eq("method needs synchronization", 0x8521);
+ __ bind(Lok);
+ }
+#endif // ASSERT
+
+ __ verify_thread();
+
+ // --------------------------------------------------------------------------
+ // JVMTI support
+ __ notify_method_entry();
+
+ // --------------------------------------------------------------------------
+ // Start executing instructions.
+ __ dispatch_next(vtos);
+
+ // --------------------------------------------------------------------------
+ // Out of line counter overflow and MDO creation code.
+ if (ProfileInterpreter) {
+ // We have decided to profile this method in the interpreter.
+ __ bind(profile_method);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method));
+ __ set_method_data_pointer_for_bcp();
+ __ b(profile_method_continue);
+ }
+
+ if (inc_counter) {
+ // Handle invocation counter overflow.
+ __ bind(invocation_counter_overflow);
+ generate_counter_overflow(profile_method_continue);
+ }
+ return entry;
+}
+
+// =============================================================================
+// Entry points
+
+address AbstractInterpreterGenerator::generate_method_entry(
+ AbstractInterpreter::MethodKind kind) {
+ // Determine code generation flags.
+ bool synchronized = false;
+ address entry_point = NULL;
+
+ switch (kind) {
+ case Interpreter::zerolocals : break;
+ case Interpreter::zerolocals_synchronized: synchronized = true; break;
+ case Interpreter::native : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(false); break;
+ case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*) this)->generate_native_entry(true); break;
+ case Interpreter::empty : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry(); break;
+ case Interpreter::accessor : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry(); break;
+ case Interpreter::abstract : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break;
+
+ case Interpreter::java_lang_math_sin : // fall thru
+ case Interpreter::java_lang_math_cos : // fall thru
+ case Interpreter::java_lang_math_tan : // fall thru
+ case Interpreter::java_lang_math_abs : // fall thru
+ case Interpreter::java_lang_math_log : // fall thru
+ case Interpreter::java_lang_math_log10 : // fall thru
+ case Interpreter::java_lang_math_sqrt : // fall thru
+ case Interpreter::java_lang_math_pow : // fall thru
+ case Interpreter::java_lang_math_exp : entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); break;
+ case Interpreter::java_lang_ref_reference_get
+ : entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break;
+ default : ShouldNotReachHere(); break;
+ }
+
+ if (entry_point) {
+ return entry_point;
+ }
+
+ return ((InterpreterGenerator*) this)->generate_normal_entry(synchronized);
+}
+
+// These should never be compiled since the interpreter will prefer
+// the compiled version to the intrinsic version.
+bool AbstractInterpreter::can_be_compiled(methodHandle m) {
+ return !math_entry_available(method_kind(m));
+}
+
+// How much stack a method activation needs in stack slots.
+// We must calc this exactly like in generate_fixed_frame.
+// Note: This returns the conservative size assuming maximum alignment.
+int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
+ const int max_alignment_size = 2;
+ const int abi_scratch = frame::abi_reg_args_size;
+ return method->max_locals() + method->max_stack() + frame::interpreter_frame_monitor_size() + max_alignment_size + abi_scratch;
+}
+
+// Fills a sceletal interpreter frame generated during deoptimizations
+// and returns the frame size in slots.
+//
+// Parameters:
+//
+// interpreter_frame == NULL:
+// Only calculate the size of an interpreter activation, no actual layout.
+// Note: This calculation must exactly parallel the frame setup
+// in TemplateInterpreter::generate_normal_entry. But it does not
+// account for the SP alignment, that might further enhance the
+// frame size, depending on FP.
+//
+// interpreter_frame != NULL:
+// set up the method, locals, and monitors.
+// The frame interpreter_frame, if not NULL, is guaranteed to be the
+// right size, as determined by a previous call to this method.
+// It is also guaranteed to be walkable even though it is in a skeletal state
+//
+// is_top_frame == true:
+// We're processing the *oldest* interpreter frame!
+//
+// pop_frame_extra_args:
+// If this is != 0 we are returning to a deoptimized frame by popping
+// off the callee frame. We want to re-execute the call that called the
+// callee interpreted, but since the return to the interpreter would pop
+// the arguments off advance the esp by dummy popframe_extra_args slots.
+// Popping off those will establish the stack layout as it was before the call.
+//
+int AbstractInterpreter::layout_activation(Method* method,
+ int tempcount,
+ int popframe_extra_args,
+ int moncount,
+ int caller_actual_parameters,
+ int callee_param_count,
+ int callee_locals,
+ frame* caller,
+ frame* interpreter_frame,
+ bool is_top_frame,
+ bool is_bottom_frame) {
+
+ const int max_alignment_space = 2;
+ const int abi_scratch = is_top_frame ? (frame::abi_reg_args_size / Interpreter::stackElementSize) :
+ (frame::abi_minframe_size / Interpreter::stackElementSize) ;
+ const int conservative_framesize_in_slots =
+ method->max_stack() + callee_locals - callee_param_count +
+ (moncount * frame::interpreter_frame_monitor_size()) + max_alignment_space +
+ abi_scratch + frame::ijava_state_size / Interpreter::stackElementSize;
+
+ assert(!is_top_frame || conservative_framesize_in_slots * 8 > frame::abi_reg_args_size + frame::ijava_state_size, "frame too small");
+
+ if (interpreter_frame == NULL) {
+ // Since we don't know the exact alignment, we return the conservative size.
+ return (conservative_framesize_in_slots & -2);
+ } else {
+ // Now we know our caller, calc the exact frame layout and size.
+ intptr_t* locals_base = (caller->is_interpreted_frame()) ?
+ caller->interpreter_frame_esp() + caller_actual_parameters :
+ caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize) ;
+
+ intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize ;
+ intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size());
+ intptr_t* esp_base = monitor - 1;
+ intptr_t* esp = esp_base - tempcount - popframe_extra_args;
+ intptr_t* sp = (intptr_t *) (((intptr_t) (esp_base- callee_locals + callee_param_count - method->max_stack()- abi_scratch)) & -StackAlignmentInBytes);
+ intptr_t* sender_sp = caller->sp() + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize;
+ intptr_t* top_frame_sp = is_top_frame ? sp : sp + (frame::abi_minframe_size - frame::abi_reg_args_size) / Interpreter::stackElementSize;
+
+ interpreter_frame->interpreter_frame_set_method(method);
+ interpreter_frame->interpreter_frame_set_locals(locals_base);
+ interpreter_frame->interpreter_frame_set_cpcache(method->constants()->cache());
+ interpreter_frame->interpreter_frame_set_esp(esp);
+ interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor);
+ interpreter_frame->interpreter_frame_set_top_frame_sp(top_frame_sp);
+ if (!is_bottom_frame) {
+ interpreter_frame->interpreter_frame_set_sender_sp(sender_sp);
+ }
+
+ int framesize_in_slots = caller->sp() - sp;
+ assert(!is_top_frame ||framesize_in_slots >= (frame::abi_reg_args_size / Interpreter::stackElementSize) + frame::ijava_state_size / Interpreter::stackElementSize, "frame too small");
+ assert(framesize_in_slots <= conservative_framesize_in_slots, "exact frame size must be smaller than the convervative size!");
+ return framesize_in_slots;
+ }
+}
+
+// =============================================================================
+// Exceptions
+
+void TemplateInterpreterGenerator::generate_throw_exception() {
+ Register Rexception = R17_tos,
+ Rcontinuation = R3_RET;
+
+ // --------------------------------------------------------------------------
+ // Entry point if an method returns with a pending exception (rethrow).
+ Interpreter::_rethrow_exception_entry = __ pc();
+ {
+ __ restore_interpreter_state(R11_scratch1); // Sets R11_scratch1 = fp.
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+
+ // Compiled code destroys templateTableBase, reload.
+ __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
+ }
+
+ // Entry point if a interpreted method throws an exception (throw).
+ Interpreter::_throw_exception_entry = __ pc();
+ {
+ __ mr(Rexception, R3_RET);
+
+ __ verify_thread();
+ __ verify_oop(Rexception);
+
+ // Expression stack must be empty before entering the VM in case of an exception.
+ __ empty_expression_stack();
+ // Find exception handler address and preserve exception oop.
+ // Call C routine to find handler and jump to it.
+ __ call_VM(Rexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Rexception);
+ __ mtctr(Rcontinuation);
+ // Push exception for exception handler bytecodes.
+ __ push_ptr(Rexception);
+
+ // Jump to exception handler (may be remove activation entry!).
+ __ bctr();
+ }
+
+ // If the exception is not handled in the current frame the frame is
+ // removed and the exception is rethrown (i.e. exception
+ // continuation is _rethrow_exception).
+ //
+ // Note: At this point the bci is still the bxi for the instruction
+ // which caused the exception and the expression stack is
+ // empty. Thus, for any VM calls at this point, GC will find a legal
+ // oop map (with empty expression stack).
+
+ // In current activation
+ // tos: exception
+ // bcp: exception bcp
+
+ // --------------------------------------------------------------------------
+ // JVMTI PopFrame support
+
+ Interpreter::_remove_activation_preserving_args_entry = __ pc();
+ {
+ // Set the popframe_processing bit in popframe_condition indicating that we are
+ // currently handling popframe, so that call_VMs that may happen later do not
+ // trigger new popframe handling cycles.
+ __ lwz(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+ __ ori(R11_scratch1, R11_scratch1, JavaThread::popframe_processing_bit);
+ __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Empty the expression stack, as in normal exception handling.
+ __ empty_expression_stack();
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false);
+
+ // Check to see whether we are returning to a deoptimized frame.
+ // (The PopFrame call ensures that the caller of the popped frame is
+ // either interpreted or compiled and deoptimizes it if compiled.)
+ // Note that we don't compare the return PC against the
+ // deoptimization blob's unpack entry because of the presence of
+ // adapter frames in C2.
+ Label Lcaller_not_deoptimized;
+ Register return_pc = R3_ARG1;
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), return_pc);
+ __ cmpdi(CCR0, R3_RET, 0);
+ __ bne(CCR0, Lcaller_not_deoptimized);
+
+ // The deoptimized case.
+ // In this case, we can't call dispatch_next() after the frame is
+ // popped, but instead must save the incoming arguments and restore
+ // them after deoptimization has occurred.
+ __ ld(R4_ARG2, in_bytes(Method::const_offset()), R19_method);
+ __ lhz(R4_ARG2 /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), R4_ARG2);
+ __ slwi(R4_ARG2, R4_ARG2, Interpreter::logStackElementSize);
+ __ addi(R5_ARG3, R18_locals, Interpreter::stackElementSize);
+ __ subf(R5_ARG3, R4_ARG2, R5_ARG3);
+ // Save these arguments.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), R16_thread, R4_ARG2, R5_ARG3);
+
+ // Inform deoptimization that it is responsible for restoring these arguments.
+ __ load_const_optimized(R11_scratch1, JavaThread::popframe_force_deopt_reexecution_bit);
+ __ stw(R11_scratch1, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Return from the current method into the deoptimization blob. Will eventually
+ // end up in the deopt interpeter entry, deoptimization prepared everything that
+ // we will reexecute the call that called us.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*reload return_pc*/ return_pc, R11_scratch1, R12_scratch2);
+ __ mtlr(return_pc);
+ __ blr();
+
+ // The non-deoptimized case.
+ __ bind(Lcaller_not_deoptimized);
+
+ // Clear the popframe condition flag.
+ __ li(R0, 0);
+ __ stw(R0, in_bytes(JavaThread::popframe_condition_offset()), R16_thread);
+
+ // Get out of the current method and re-execute the call that called us.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ return_pc, R11_scratch1, R12_scratch2);
+ __ restore_interpreter_state(R11_scratch1);
+ __ ld(R12_scratch2, _ijava_state_neg(top_frame_sp), R11_scratch1);
+ __ resize_frame_absolute(R12_scratch2, R11_scratch1, R0);
+ __ mtlr(return_pc);
+ if (ProfileInterpreter) {
+ __ set_method_data_pointer_for_bcp();
+ }
+ __ dispatch_next(vtos);
+ }
+ // end of JVMTI PopFrame support
+
+ // --------------------------------------------------------------------------
+ // Remove activation exception entry.
+ // This is jumped to if an interpreted method can't handle an exception itself
+ // (we come from the throw/rethrow exception entry above). We're going to call
+ // into the VM to find the exception handler in the caller, pop the current
+ // frame and return the handler we calculated.
+ Interpreter::_remove_activation_entry = __ pc();
+ {
+ __ pop_ptr(Rexception);
+ __ verify_thread();
+ __ verify_oop(Rexception);
+ __ std(Rexception, in_bytes(JavaThread::vm_result_offset()), R16_thread);
+
+ __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, true);
+ __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI, false);
+
+ __ get_vm_result(Rexception);
+
+ // We are done with this activation frame; find out where to go next.
+ // The continuation point will be an exception handler, which expects
+ // the following registers set up:
+ //
+ // RET: exception oop
+ // ARG2: Issuing PC (see generate_exception_blob()), only used if the caller is compiled.
+
+ Register return_pc = R31; // Needs to survive the runtime call.
+ __ ld(return_pc, 0, R1_SP);
+ __ ld(return_pc, _abi(lr), return_pc);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, return_pc);
+
+ // Remove the current activation.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ noreg, R11_scratch1, R12_scratch2);
+
+ __ mr(R4_ARG2, return_pc);
+ __ mtlr(R3_RET);
+ __ mr(R3_RET, Rexception);
+ __ blr();
+ }
+}
+
+// JVMTI ForceEarlyReturn support.
+// Returns "in the middle" of a method with a "fake" return value.
+address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) {
+
+ Register Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2;
+
+ address entry = __ pc();
+ __ empty_expression_stack();
+
+ __ load_earlyret_value(state, Rscratch1);
+
+ __ ld(Rscratch1, in_bytes(JavaThread::jvmti_thread_state_offset()), R16_thread);
+ // Clear the earlyret state.
+ __ li(R0, 0);
+ __ stw(R0, in_bytes(JvmtiThreadState::earlyret_state_offset()), Rscratch1);
+
+ __ remove_activation(state, false, false);
+ // Copied from TemplateTable::_return.
+ // Restoration of lr done by remove_activation.
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R3_RET, R17_tos); break;
+ case ftos:
+ case dtos: __ fmr(F1_RET, F15_ftos); break;
+ case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
+ // to get visible before the reference to the object gets stored anywhere.
+ __ membar(Assembler::StoreStore); break;
+ default : ShouldNotReachHere();
+ }
+ __ blr();
+
+ return entry;
+} // end of ForceEarlyReturn support
+
+//-----------------------------------------------------------------------------
+// Helper for vtos entry point generation
+
+void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t,
+ address& bep,
+ address& cep,
+ address& sep,
+ address& aep,
+ address& iep,
+ address& lep,
+ address& fep,
+ address& dep,
+ address& vep) {
+ assert(t->is_valid() && t->tos_in() == vtos, "illegal template");
+ Label L;
+
+ aep = __ pc(); __ push_ptr(); __ b(L);
+ fep = __ pc(); __ push_f(); __ b(L);
+ dep = __ pc(); __ push_d(); __ b(L);
+ lep = __ pc(); __ push_l(); __ b(L);
+ __ align(32, 12, 24); // align L
+ bep = cep = sep =
+ iep = __ pc(); __ push_i();
+ vep = __ pc();
+ __ bind(L);
+ generate_and_dispatch(t);
+}
+
+//-----------------------------------------------------------------------------
+// Generation of individual instructions
+
+// helpers for generate_and_dispatch
+
+InterpreterGenerator::InterpreterGenerator(StubQueue* code)
+ : TemplateInterpreterGenerator(code) {
+ generate_all(); // Down here so it can be "virtual".
+}
+
+//-----------------------------------------------------------------------------
+
+// Non-product code
+#ifndef PRODUCT
+address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
+ //__ flush_bundle();
+ address entry = __ pc();
+
+ char *bname = NULL;
+ uint tsize = 0;
+ switch(state) {
+ case ftos:
+ bname = "trace_code_ftos {";
+ tsize = 2;
+ break;
+ case btos:
+ bname = "trace_code_btos {";
+ tsize = 2;
+ break;
+ case ctos:
+ bname = "trace_code_ctos {";
+ tsize = 2;
+ break;
+ case stos:
+ bname = "trace_code_stos {";
+ tsize = 2;
+ break;
+ case itos:
+ bname = "trace_code_itos {";
+ tsize = 2;
+ break;
+ case ltos:
+ bname = "trace_code_ltos {";
+ tsize = 3;
+ break;
+ case atos:
+ bname = "trace_code_atos {";
+ tsize = 2;
+ break;
+ case vtos:
+ // Note: In case of vtos, the topmost of stack value could be a int or doubl
+ // In case of a double (2 slots) we won't see the 2nd stack value.
+ // Maybe we simply should print the topmost 3 stack slots to cope with the problem.
+ bname = "trace_code_vtos {";
+ tsize = 2;
+
+ break;
+ case dtos:
+ bname = "trace_code_dtos {";
+ tsize = 3;
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ BLOCK_COMMENT(bname);
+
+ // Support short-cut for TraceBytecodesAt.
+ // Don't call into the VM if we don't want to trace to speed up things.
+ Label Lskip_vm_call;
+ if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
+ int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true);
+ int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
+ __ ld(R11_scratch1, offs1, R11_scratch1);
+ __ lwa(R12_scratch2, offs2, R12_scratch2);
+ __ cmpd(CCR0, R12_scratch2, R11_scratch1);
+ __ blt(CCR0, Lskip_vm_call);
+ }
+
+ __ push(state);
+ // Load 2 topmost expression stack values.
+ __ ld(R6_ARG4, tsize*Interpreter::stackElementSize, R15_esp);
+ __ ld(R5_ARG3, Interpreter::stackElementSize, R15_esp);
+ __ mflr(R31);
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::trace_bytecode), /* unused */ R4_ARG2, R5_ARG3, R6_ARG4, false);
+ __ mtlr(R31);
+ __ pop(state);
+
+ if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
+ __ bind(Lskip_vm_call);
+ }
+ __ blr();
+ BLOCK_COMMENT("} trace_code");
+ return entry;
+}
+
+void TemplateInterpreterGenerator::count_bytecode() {
+ int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true);
+ __ lwz(R12_scratch2, offs, R11_scratch1);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, offs, R11_scratch1);
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
+ int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeHistogram::_counters[t->bytecode()], R12_scratch2, true);
+ __ lwz(R12_scratch2, offs, R11_scratch1);
+ __ addi(R12_scratch2, R12_scratch2, 1);
+ __ stw(R12_scratch2, offs, R11_scratch1);
+}
+
+void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) {
+ const Register addr = R11_scratch1,
+ tmp = R12_scratch2;
+ // Get index, shift out old bytecode, bring in new bytecode, and store it.
+ // _index = (_index >> log2_number_of_codes) |
+ // (bytecode << log2_number_of_codes);
+ int offs1 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_index, tmp, true);
+ __ lwz(tmp, offs1, addr);
+ __ srwi(tmp, tmp, BytecodePairHistogram::log2_number_of_codes);
+ __ ori(tmp, tmp, ((int) t->bytecode()) << BytecodePairHistogram::log2_number_of_codes);
+ __ stw(tmp, offs1, addr);
+
+ // Bump bucket contents.
+ // _counters[_index] ++;
+ int offs2 = __ load_const_optimized(addr, (address)&BytecodePairHistogram::_counters, R0, true);
+ __ sldi(tmp, tmp, LogBytesPerInt);
+ __ add(addr, tmp, addr);
+ __ lwz(tmp, offs2, addr);
+ __ addi(tmp, tmp, 1);
+ __ stw(tmp, offs2, addr);
+}
+
+void TemplateInterpreterGenerator::trace_bytecode(Template* t) {
+ // Call a little run-time stub to avoid blow-up for each bytecode.
+ // The run-time runtime saves the right registers, depending on
+ // the tosca in-state for the given template.
+
+ assert(Interpreter::trace_code(t->tos_in()) != NULL,
+ "entry must have been generated");
+
+ // Note: we destroy LR here.
+ __ bl(Interpreter::trace_code(t->tos_in()));
+}
+
+void TemplateInterpreterGenerator::stop_interpreter_at() {
+ Label L;
+ int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true);
+ int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
+ __ ld(R11_scratch1, offs1, R11_scratch1);
+ __ lwa(R12_scratch2, offs2, R12_scratch2);
+ __ cmpd(CCR0, R12_scratch2, R11_scratch1);
+ __ bne(CCR0, L);
+ __ illtrap();
+ __ bind(L);
+}
+
+#endif // !PRODUCT
+#endif // !CC_INTERP
diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
new file mode 100644
index 00000000000..eb817b0a256
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP
+#define CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP
+
+ protected:
+
+ // Size of interpreter code. Increase if too small. Interpreter will
+ // fail with a guarantee ("not enough space for interpreter generation");
+ // if too small.
+ // Run with +PrintInterpreter to get the VM to print out the size.
+ // Max size with JVMTI
+
+ const static int InterpreterCodeSize = 210*K;
+
+#endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP
+
+
diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp
new file mode 100644
index 00000000000..e7846bc2859
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp
@@ -0,0 +1,4082 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/interpreterRuntime.hpp"
+#include "interpreter/templateInterpreter.hpp"
+#include "interpreter/templateTable.hpp"
+#include "memory/universe.inline.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "oops/oop.inline.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/synchronizer.hpp"
+#include "utilities/macros.hpp"
+
+#ifndef CC_INTERP
+
+#undef __
+#define __ _masm->
+
+// ============================================================================
+// Misc helpers
+
+// Do an oop store like *(base + index) = val OR *(base + offset) = val
+// (only one of both variants is possible at the same time).
+// Index can be noreg.
+// Kills:
+// Rbase, Rtmp
+static void do_oop_store(InterpreterMacroAssembler* _masm,
+ Register Rbase,
+ RegisterOrConstant offset,
+ Register Rval, // Noreg means always null.
+ Register Rtmp1,
+ Register Rtmp2,
+ Register Rtmp3,
+ BarrierSet::Name barrier,
+ bool precise,
+ bool check_null) {
+ assert_different_registers(Rtmp1, Rtmp2, Rtmp3, Rval, Rbase);
+
+ switch (barrier) {
+#ifndef SERIALGC
+ case BarrierSet::G1SATBCT:
+ case BarrierSet::G1SATBCTLogging:
+ {
+ // Load and record the previous value.
+ __ g1_write_barrier_pre(Rbase, offset,
+ Rtmp3, /* holder of pre_val ? */
+ Rtmp1, Rtmp2, false /* frame */);
+
+ Label Lnull, Ldone;
+ if (Rval != noreg) {
+ if (check_null) {
+ __ cmpdi(CCR0, Rval, 0);
+ __ beq(CCR0, Lnull);
+ }
+ __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval must stay uncompressed.*/ Rtmp1);
+ // Mark the card.
+ if (!(offset.is_constant() && offset.as_constant() == 0) && precise) {
+ __ add(Rbase, offset, Rbase);
+ }
+ __ g1_write_barrier_post(Rbase, Rval, Rtmp1, Rtmp2, Rtmp3, /*filtered (fast path)*/ &Ldone);
+ if (check_null) { __ b(Ldone); }
+ }
+
+ if (Rval == noreg || check_null) { // Store null oop.
+ Register Rnull = Rval;
+ __ bind(Lnull);
+ if (Rval == noreg) {
+ Rnull = Rtmp1;
+ __ li(Rnull, 0);
+ }
+ if (UseCompressedOops) {
+ __ stw(Rnull, offset, Rbase);
+ } else {
+ __ std(Rnull, offset, Rbase);
+ }
+ }
+ __ bind(Ldone);
+ }
+ break;
+#endif // SERIALGC
+ case BarrierSet::CardTableModRef:
+ case BarrierSet::CardTableExtension:
+ {
+ Label Lnull, Ldone;
+ if (Rval != noreg) {
+ if (check_null) {
+ __ cmpdi(CCR0, Rval, 0);
+ __ beq(CCR0, Lnull);
+ }
+ __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval should better stay uncompressed.*/ Rtmp1);
+ // Mark the card.
+ if (!(offset.is_constant() && offset.as_constant() == 0) && precise) {
+ __ add(Rbase, offset, Rbase);
+ }
+ __ card_write_barrier_post(Rbase, Rval, Rtmp1);
+ if (check_null) {
+ __ b(Ldone);
+ }
+ }
+
+ if (Rval == noreg || check_null) { // Store null oop.
+ Register Rnull = Rval;
+ __ bind(Lnull);
+ if (Rval == noreg) {
+ Rnull = Rtmp1;
+ __ li(Rnull, 0);
+ }
+ if (UseCompressedOops) {
+ __ stw(Rnull, offset, Rbase);
+ } else {
+ __ std(Rnull, offset, Rbase);
+ }
+ }
+ __ bind(Ldone);
+ }
+ break;
+ case BarrierSet::ModRef:
+ case BarrierSet::Other:
+ ShouldNotReachHere();
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+// ============================================================================
+// Platform-dependent initialization
+
+void TemplateTable::pd_initialize() {
+ // No ppc64 specific initialization.
+}
+
+Address TemplateTable::at_bcp(int offset) {
+ // Not used on ppc.
+ ShouldNotReachHere();
+ return Address();
+}
+
+// Patches the current bytecode (ptr to it located in bcp)
+// in the bytecode stream with a new one.
+void TemplateTable::patch_bytecode(Bytecodes::Code new_bc, Register Rnew_bc, Register Rtemp, bool load_bc_into_bc_reg /*=true*/, int byte_no) {
+ // With sharing on, may need to test method flag.
+ if (!RewriteBytecodes) return;
+ Label L_patch_done;
+
+ switch (new_bc) {
+ case Bytecodes::_fast_aputfield:
+ case Bytecodes::_fast_bputfield:
+ case Bytecodes::_fast_cputfield:
+ case Bytecodes::_fast_dputfield:
+ case Bytecodes::_fast_fputfield:
+ case Bytecodes::_fast_iputfield:
+ case Bytecodes::_fast_lputfield:
+ case Bytecodes::_fast_sputfield:
+ {
+ // We skip bytecode quickening for putfield instructions when
+ // the put_code written to the constant pool cache is zero.
+ // This is required so that every execution of this instruction
+ // calls out to InterpreterRuntime::resolve_get_put to do
+ // additional, required work.
+ assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
+ assert(load_bc_into_bc_reg, "we use bc_reg as temp");
+ __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1);
+ // Big Endian: ((*(cache+indices))>>((1+byte_no)*8))&0xFF
+ __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp);
+ __ cmpwi(CCR0, Rnew_bc, 0);
+ __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc);
+ __ beq(CCR0, L_patch_done);
+ // __ isync(); // acquire not needed
+ break;
+ }
+
+ default:
+ assert(byte_no == -1, "sanity");
+ if (load_bc_into_bc_reg) {
+ __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc);
+ }
+ }
+
+ if (JvmtiExport::can_post_breakpoint()) {
+ Label L_fast_patch;
+ __ lbz(Rtemp, 0, R14_bcp);
+ __ cmpwi(CCR0, Rtemp, (unsigned int)(unsigned char)Bytecodes::_breakpoint);
+ __ bne(CCR0, L_fast_patch);
+ // Perform the quickening, slowly, in the bowels of the breakpoint table.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), R19_method, R14_bcp, Rnew_bc);
+ __ b(L_patch_done);
+ __ bind(L_fast_patch);
+ }
+
+ // Patch bytecode.
+ __ stb(Rnew_bc, 0, R14_bcp);
+
+ __ bind(L_patch_done);
+}
+
+// ============================================================================
+// Individual instructions
+
+void TemplateTable::nop() {
+ transition(vtos, vtos);
+ // Nothing to do.
+}
+
+void TemplateTable::shouldnotreachhere() {
+ transition(vtos, vtos);
+ __ stop("shouldnotreachhere bytecode");
+}
+
+void TemplateTable::aconst_null() {
+ transition(vtos, atos);
+ __ li(R17_tos, 0);
+}
+
+void TemplateTable::iconst(int value) {
+ transition(vtos, itos);
+ assert(value >= -1 && value <= 5, "");
+ __ li(R17_tos, value);
+}
+
+void TemplateTable::lconst(int value) {
+ transition(vtos, ltos);
+ assert(value >= -1 && value <= 5, "");
+ __ li(R17_tos, value);
+}
+
+void TemplateTable::fconst(int value) {
+ transition(vtos, ftos);
+ static float zero = 0.0;
+ static float one = 1.0;
+ static float two = 2.0;
+ switch (value) {
+ default: ShouldNotReachHere();
+ case 0: {
+ int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0);
+ __ lfs(F15_ftos, simm16_offset, R11_scratch1);
+ break;
+ }
+ case 1: {
+ int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0);
+ __ lfs(F15_ftos, simm16_offset, R11_scratch1);
+ break;
+ }
+ case 2: {
+ int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&two, R0);
+ __ lfs(F15_ftos, simm16_offset, R11_scratch1);
+ break;
+ }
+ }
+}
+
+void TemplateTable::dconst(int value) {
+ transition(vtos, dtos);
+ static double zero = 0.0;
+ static double one = 1.0;
+ switch (value) {
+ case 0: {
+ int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&zero, R0);
+ __ lfd(F15_ftos, simm16_offset, R11_scratch1);
+ break;
+ }
+ case 1: {
+ int simm16_offset = __ load_const_optimized(R11_scratch1, (address*)&one, R0);
+ __ lfd(F15_ftos, simm16_offset, R11_scratch1);
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+}
+
+void TemplateTable::bipush() {
+ transition(vtos, itos);
+ __ lbz(R17_tos, 1, R14_bcp);
+ __ extsb(R17_tos, R17_tos);
+}
+
+void TemplateTable::sipush() {
+ transition(vtos, itos);
+ __ get_2_byte_integer_at_bcp(1, R17_tos, InterpreterMacroAssembler::Signed);
+}
+
+void TemplateTable::ldc(bool wide) {
+ Register Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rcpool = R3_ARG1;
+
+ transition(vtos, vtos);
+ Label notInt, notClass, exit;
+
+ __ get_cpool_and_tags(Rcpool, Rscratch2); // Set Rscratch2 = &tags.
+ if (wide) { // Read index.
+ __ get_2_byte_integer_at_bcp(1, Rscratch1, InterpreterMacroAssembler::Unsigned);
+ } else {
+ __ lbz(Rscratch1, 1, R14_bcp);
+ }
+
+ const int base_offset = ConstantPool::header_size() * wordSize;
+ const int tags_offset = Array::base_offset_in_bytes();
+
+ // Get type from tags.
+ __ addi(Rscratch2, Rscratch2, tags_offset);
+ __ lbzx(Rscratch2, Rscratch2, Rscratch1);
+
+ __ cmpwi(CCR0, Rscratch2, JVM_CONSTANT_UnresolvedClass); // Unresolved class?
+ __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_UnresolvedClassInError); // Unresolved class in error state?
+ __ cror(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
+
+ // Resolved class - need to call vm to get java mirror of the class.
+ __ cmpwi(CCR1, Rscratch2, JVM_CONSTANT_Class);
+ __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // Neither resolved class nor unresolved case from above?
+ __ beq(CCR0, notClass);
+
+ __ li(R4, wide ? 1 : 0);
+ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), R4);
+ __ push(atos);
+ __ b(exit);
+
+ __ align(32, 12);
+ __ bind(notClass);
+ __ addi(Rcpool, Rcpool, base_offset);
+ __ sldi(Rscratch1, Rscratch1, LogBytesPerWord);
+ __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Integer);
+ __ bne(CCR0, notInt);
+ __ isync(); // Order load of constant wrt. tags.
+ __ lwax(R17_tos, Rcpool, Rscratch1);
+ __ push(itos);
+ __ b(exit);
+
+ __ align(32, 12);
+ __ bind(notInt);
+#ifdef ASSERT
+ // String and Object are rewritten to fast_aldc
+ __ cmpdi(CCR0, Rscratch2, JVM_CONSTANT_Float);
+ __ asm_assert_eq("unexpected type", 0x8765);
+#endif
+ __ isync(); // Order load of constant wrt. tags.
+ __ lfsx(F15_ftos, Rcpool, Rscratch1);
+ __ push(ftos);
+
+ __ align(32, 12);
+ __ bind(exit);
+}
+
+// Fast path for caching oop constants.
+void TemplateTable::fast_aldc(bool wide) {
+ transition(vtos, atos);
+
+ int index_size = wide ? sizeof(u2) : sizeof(u1);
+ const Register Rscratch = R11_scratch1;
+ Label resolved;
+
+ // We are resolved if the resolved reference cache entry contains a
+ // non-null object (CallSite, etc.)
+ __ get_cache_index_at_bcp(Rscratch, 1, index_size); // Load index.
+ __ load_resolved_reference_at_index(R17_tos, Rscratch);
+ __ cmpdi(CCR0, R17_tos, 0);
+ __ bne(CCR0, resolved);
+ __ load_const_optimized(R3_ARG1, (int)bytecode());
+
+ address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
+
+ // First time invocation - must resolve first.
+ __ call_VM(R17_tos, entry, R3_ARG1);
+
+ __ align(32, 12);
+ __ bind(resolved);
+ __ verify_oop(R17_tos);
+}
+
+void TemplateTable::ldc2_w() {
+ transition(vtos, vtos);
+ Label Llong, Lexit;
+
+ Register Rindex = R11_scratch1,
+ Rcpool = R12_scratch2,
+ Rtag = R3_ARG1;
+ __ get_cpool_and_tags(Rcpool, Rtag);
+ __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned);
+
+ const int base_offset = ConstantPool::header_size() * wordSize;
+ const int tags_offset = Array::base_offset_in_bytes();
+ // Get type from tags.
+ __ addi(Rcpool, Rcpool, base_offset);
+ __ addi(Rtag, Rtag, tags_offset);
+
+ __ lbzx(Rtag, Rtag, Rindex);
+
+ __ sldi(Rindex, Rindex, LogBytesPerWord);
+ __ cmpdi(CCR0, Rtag, JVM_CONSTANT_Double);
+ __ bne(CCR0, Llong);
+ // A double can be placed at word-aligned locations in the constant pool.
+ // Check out Conversions.java for an example.
+ // Also ConstantPool::header_size() is 20, which makes it very difficult
+ // to double-align double on the constant pool. SG, 11/7/97
+ __ isync(); // Order load of constant wrt. tags.
+ __ lfdx(F15_ftos, Rcpool, Rindex);
+ __ push(dtos);
+ __ b(Lexit);
+
+ __ bind(Llong);
+ __ isync(); // Order load of constant wrt. tags.
+ __ ldx(R17_tos, Rcpool, Rindex);
+ __ push(ltos);
+
+ __ bind(Lexit);
+}
+
+// Get the locals index located in the bytecode stream at bcp + offset.
+void TemplateTable::locals_index(Register Rdst, int offset) {
+ __ lbz(Rdst, offset, R14_bcp);
+}
+
+void TemplateTable::iload() {
+ transition(vtos, itos);
+
+ // Get the local value into tos
+ const Register Rindex = R22_tmp2;
+ locals_index(Rindex);
+
+ // Rewrite iload,iload pair into fast_iload2
+ // iload,caload pair into fast_icaload
+ if (RewriteFrequentPairs) {
+ Label Lrewrite, Ldone;
+ Register Rnext_byte = R3_ARG1,
+ Rrewrite_to = R6_ARG4,
+ Rscratch = R11_scratch1;
+
+ // get next byte
+ __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_iload), R14_bcp);
+
+ // if _iload, wait to rewrite to iload2. We only want to rewrite the
+ // last two iloads in a pair. Comparing against fast_iload means that
+ // the next bytecode is neither an iload or a caload, and therefore
+ // an iload pair.
+ __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_iload);
+ __ beq(CCR0, Ldone);
+
+ __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_iload);
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload2);
+ __ beq(CCR1, Lrewrite);
+
+ __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_caload);
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_icaload);
+ __ beq(CCR0, Lrewrite);
+
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iload);
+
+ __ bind(Lrewrite);
+ patch_bytecode(Bytecodes::_iload, Rrewrite_to, Rscratch, false);
+ __ bind(Ldone);
+ }
+
+ __ load_local_int(R17_tos, Rindex, Rindex);
+}
+
+// Load 2 integers in a row without dispatching
+void TemplateTable::fast_iload2() {
+ transition(vtos, itos);
+
+ __ lbz(R3_ARG1, 1, R14_bcp);
+ __ lbz(R17_tos, Bytecodes::length_for(Bytecodes::_iload) + 1, R14_bcp);
+
+ __ load_local_int(R3_ARG1, R11_scratch1, R3_ARG1);
+ __ load_local_int(R17_tos, R12_scratch2, R17_tos);
+ __ push_i(R3_ARG1);
+}
+
+void TemplateTable::fast_iload() {
+ transition(vtos, itos);
+ // Get the local value into tos
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ load_local_int(R17_tos, Rindex, Rindex);
+}
+
+// Load a local variable type long from locals area to TOS cache register.
+// Local index resides in bytecodestream.
+void TemplateTable::lload() {
+ transition(vtos, ltos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ load_local_long(R17_tos, Rindex, Rindex);
+}
+
+void TemplateTable::fload() {
+ transition(vtos, ftos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ load_local_float(F15_ftos, Rindex, Rindex);
+}
+
+void TemplateTable::dload() {
+ transition(vtos, dtos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ load_local_double(F15_ftos, Rindex, Rindex);
+}
+
+void TemplateTable::aload() {
+ transition(vtos, atos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ load_local_ptr(R17_tos, Rindex, Rindex);
+}
+
+void TemplateTable::locals_index_wide(Register Rdst) {
+ // Offset is 2, not 1, because Lbcp points to wide prefix code.
+ __ get_2_byte_integer_at_bcp(2, Rdst, InterpreterMacroAssembler::Unsigned);
+}
+
+void TemplateTable::wide_iload() {
+ // Get the local value into tos.
+
+ const Register Rindex = R11_scratch1;
+ locals_index_wide(Rindex);
+ __ load_local_int(R17_tos, Rindex, Rindex);
+}
+
+void TemplateTable::wide_lload() {
+ transition(vtos, ltos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index_wide(Rindex);
+ __ load_local_long(R17_tos, Rindex, Rindex);
+}
+
+void TemplateTable::wide_fload() {
+ transition(vtos, ftos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index_wide(Rindex);
+ __ load_local_float(F15_ftos, Rindex, Rindex);
+}
+
+void TemplateTable::wide_dload() {
+ transition(vtos, dtos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index_wide(Rindex);
+ __ load_local_double(F15_ftos, Rindex, Rindex);
+}
+
+void TemplateTable::wide_aload() {
+ transition(vtos, atos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index_wide(Rindex);
+ __ load_local_ptr(R17_tos, Rindex, Rindex);
+}
+
+void TemplateTable::iaload() {
+ transition(itos, itos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr);
+ __ lwa(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rload_addr);
+}
+
+void TemplateTable::laload() {
+ transition(itos, ltos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr);
+ __ ld(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rload_addr);
+}
+
+void TemplateTable::faload() {
+ transition(itos, ftos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerInt, Rtemp, Rload_addr);
+ __ lfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rload_addr);
+}
+
+void TemplateTable::daload() {
+ transition(itos, dtos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerLong, Rtemp, Rload_addr);
+ __ lfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rload_addr);
+}
+
+void TemplateTable::aaload() {
+ transition(itos, atos);
+
+ // tos: index
+ // result tos: array
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr);
+ __ load_heap_oop(R17_tos, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rload_addr);
+ __ verify_oop(R17_tos);
+ //__ dcbt(R17_tos); // prefetch
+}
+
+void TemplateTable::baload() {
+ transition(itos, itos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, 0, Rtemp, Rload_addr);
+ __ lbz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rload_addr);
+ __ extsb(R17_tos, R17_tos);
+}
+
+void TemplateTable::caload() {
+ transition(itos, itos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R5_ARG3;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
+ __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr);
+}
+
+// Iload followed by caload frequent pair.
+void TemplateTable::fast_icaload() {
+ transition(vtos, itos);
+
+ const Register Rload_addr = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rtemp = R11_scratch1;
+
+ locals_index(R17_tos);
+ __ load_local_int(R17_tos, Rtemp, R17_tos);
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
+ __ lhz(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rload_addr);
+}
+
+void TemplateTable::saload() {
+ transition(itos, itos);
+
+ const Register Rload_addr = R11_scratch1,
+ Rarray = R12_scratch2,
+ Rtemp = R3_ARG1;
+ __ index_check(Rarray, R17_tos /* index */, LogBytesPerShort, Rtemp, Rload_addr);
+ __ lha(R17_tos, arrayOopDesc::base_offset_in_bytes(T_SHORT), Rload_addr);
+}
+
+void TemplateTable::iload(int n) {
+ transition(vtos, itos);
+
+ __ lwz(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::lload(int n) {
+ transition(vtos, ltos);
+
+ __ ld(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
+}
+
+void TemplateTable::fload(int n) {
+ transition(vtos, ftos);
+
+ __ lfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::dload(int n) {
+ transition(vtos, dtos);
+
+ __ lfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
+}
+
+void TemplateTable::aload(int n) {
+ transition(vtos, atos);
+
+ __ ld(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::aload_0() {
+ transition(vtos, atos);
+ // According to bytecode histograms, the pairs:
+ //
+ // _aload_0, _fast_igetfield
+ // _aload_0, _fast_agetfield
+ // _aload_0, _fast_fgetfield
+ //
+ // occur frequently. If RewriteFrequentPairs is set, the (slow)
+ // _aload_0 bytecode checks if the next bytecode is either
+ // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then
+ // rewrites the current bytecode into a pair bytecode; otherwise it
+ // rewrites the current bytecode into _0 that doesn't do
+ // the pair check anymore.
+ //
+ // Note: If the next bytecode is _getfield, the rewrite must be
+ // delayed, otherwise we may miss an opportunity for a pair.
+ //
+ // Also rewrite frequent pairs
+ // aload_0, aload_1
+ // aload_0, iload_1
+ // These bytecodes with a small amount of code are most profitable
+ // to rewrite.
+
+ if (RewriteFrequentPairs) {
+
+ Label Lrewrite, Ldont_rewrite;
+ Register Rnext_byte = R3_ARG1,
+ Rrewrite_to = R6_ARG4,
+ Rscratch = R11_scratch1;
+
+ // Get next byte.
+ __ lbz(Rnext_byte, Bytecodes::length_for(Bytecodes::_aload_0), R14_bcp);
+
+ // If _getfield, wait to rewrite. We only want to rewrite the last two bytecodes in a pair.
+ __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_getfield);
+ __ beq(CCR0, Ldont_rewrite);
+
+ __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_igetfield);
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_iaccess_0);
+ __ beq(CCR1, Lrewrite);
+
+ __ cmpwi(CCR0, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_agetfield);
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aaccess_0);
+ __ beq(CCR0, Lrewrite);
+
+ __ cmpwi(CCR1, Rnext_byte, (unsigned int)(unsigned char)Bytecodes::_fast_fgetfield);
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_faccess_0);
+ __ beq(CCR1, Lrewrite);
+
+ __ li(Rrewrite_to, (unsigned int)(unsigned char)Bytecodes::_fast_aload_0);
+
+ __ bind(Lrewrite);
+ patch_bytecode(Bytecodes::_aload_0, Rrewrite_to, Rscratch, false);
+ __ bind(Ldont_rewrite);
+ }
+
+ // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop).
+ aload(0);
+}
+
+void TemplateTable::istore() {
+ transition(itos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ store_local_int(R17_tos, Rindex);
+}
+
+void TemplateTable::lstore() {
+ transition(ltos, vtos);
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ store_local_long(R17_tos, Rindex);
+}
+
+void TemplateTable::fstore() {
+ transition(ftos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ store_local_float(F15_ftos, Rindex);
+}
+
+void TemplateTable::dstore() {
+ transition(dtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ locals_index(Rindex);
+ __ store_local_double(F15_ftos, Rindex);
+}
+
+void TemplateTable::astore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_ptr();
+ __ verify_oop_or_return_address(R17_tos, Rindex);
+ locals_index(Rindex);
+ __ store_local_ptr(R17_tos, Rindex);
+}
+
+void TemplateTable::wide_istore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_i();
+ locals_index_wide(Rindex);
+ __ store_local_int(R17_tos, Rindex);
+}
+
+void TemplateTable::wide_lstore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_l();
+ locals_index_wide(Rindex);
+ __ store_local_long(R17_tos, Rindex);
+}
+
+void TemplateTable::wide_fstore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_f();
+ locals_index_wide(Rindex);
+ __ store_local_float(F15_ftos, Rindex);
+}
+
+void TemplateTable::wide_dstore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_d();
+ locals_index_wide(Rindex);
+ __ store_local_double(F15_ftos, Rindex);
+}
+
+void TemplateTable::wide_astore() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1;
+ __ pop_ptr();
+ __ verify_oop_or_return_address(R17_tos, Rindex);
+ locals_index_wide(Rindex);
+ __ store_local_ptr(R17_tos, Rindex);
+}
+
+void TemplateTable::iastore() {
+ transition(itos, vtos);
+
+ const Register Rindex = R3_ARG1,
+ Rstore_addr = R4_ARG2,
+ Rarray = R5_ARG3,
+ Rtemp = R6_ARG4;
+ __ pop_i(Rindex);
+ __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr);
+ __ stw(R17_tos, arrayOopDesc::base_offset_in_bytes(T_INT), Rstore_addr);
+ }
+
+void TemplateTable::lastore() {
+ transition(ltos, vtos);
+
+ const Register Rindex = R3_ARG1,
+ Rstore_addr = R4_ARG2,
+ Rarray = R5_ARG3,
+ Rtemp = R6_ARG4;
+ __ pop_i(Rindex);
+ __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr);
+ __ std(R17_tos, arrayOopDesc::base_offset_in_bytes(T_LONG), Rstore_addr);
+ }
+
+void TemplateTable::fastore() {
+ transition(ftos, vtos);
+
+ const Register Rindex = R3_ARG1,
+ Rstore_addr = R4_ARG2,
+ Rarray = R5_ARG3,
+ Rtemp = R6_ARG4;
+ __ pop_i(Rindex);
+ __ index_check(Rarray, Rindex, LogBytesPerInt, Rtemp, Rstore_addr);
+ __ stfs(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Rstore_addr);
+ }
+
+void TemplateTable::dastore() {
+ transition(dtos, vtos);
+
+ const Register Rindex = R3_ARG1,
+ Rstore_addr = R4_ARG2,
+ Rarray = R5_ARG3,
+ Rtemp = R6_ARG4;
+ __ pop_i(Rindex);
+ __ index_check(Rarray, Rindex, LogBytesPerLong, Rtemp, Rstore_addr);
+ __ stfd(F15_ftos, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Rstore_addr);
+ }
+
+// Pop 3 values from the stack and...
+void TemplateTable::aastore() {
+ transition(vtos, vtos);
+
+ Label Lstore_ok, Lis_null, Ldone;
+ const Register Rindex = R3_ARG1,
+ Rarray = R4_ARG2,
+ Rscratch = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rarray_klass = R5_ARG3,
+ Rarray_element_klass = Rarray_klass,
+ Rvalue_klass = R6_ARG4,
+ Rstore_addr = R31; // Use register which survives VM call.
+
+ __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp); // Get value to store.
+ __ lwz(Rindex, Interpreter::expr_offset_in_bytes(1), R15_esp); // Get index.
+ __ ld(Rarray, Interpreter::expr_offset_in_bytes(2), R15_esp); // Get array.
+
+ __ verify_oop(R17_tos);
+ __ index_check_without_pop(Rarray, Rindex, UseCompressedOops ? 2 : LogBytesPerWord, Rscratch, Rstore_addr);
+ // Rindex is dead!
+ Register Rscratch3 = Rindex;
+
+ // Do array store check - check for NULL value first.
+ __ cmpdi(CCR0, R17_tos, 0);
+ __ beq(CCR0, Lis_null);
+
+ __ load_klass(Rarray_klass, Rarray);
+ __ load_klass(Rvalue_klass, R17_tos);
+
+ // Do fast instanceof cache test.
+ __ ld(Rarray_element_klass, in_bytes(ObjArrayKlass::element_klass_offset()), Rarray_klass);
+
+ // Generate a fast subtype check. Branch to store_ok if no failure. Throw if failure.
+ __ gen_subtype_check(Rvalue_klass /*subklass*/, Rarray_element_klass /*superklass*/, Rscratch, Rscratch2, Rscratch3, Lstore_ok);
+
+ // Fell through: subtype check failed => throw an exception.
+ __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArrayStoreException_entry);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ __ bind(Lis_null);
+ do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */,
+ Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */);
+ __ profile_null_seen(Rscratch, Rscratch2);
+ __ b(Ldone);
+
+ // Store is OK.
+ __ bind(Lstore_ok);
+ do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
+ Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */);
+
+ __ bind(Ldone);
+ // Adjust sp (pops array, index and value).
+ __ addi(R15_esp, R15_esp, 3 * Interpreter::stackElementSize);
+}
+
+void TemplateTable::bastore() {
+ transition(itos, vtos);
+
+ const Register Rindex = R11_scratch1,
+ Rarray = R12_scratch2,
+ Rscratch = R3_ARG1;
+ __ pop_i(Rindex);
+ // tos: val
+ // Rarray: array ptr (popped by index_check)
+ __ index_check(Rarray, Rindex, 0, Rscratch, Rarray);
+ __ stb(R17_tos, arrayOopDesc::base_offset_in_bytes(T_BYTE), Rarray);
+}
+
+void TemplateTable::castore() {
+ transition(itos, vtos);
+
+ const Register Rindex = R11_scratch1,
+ Rarray = R12_scratch2,
+ Rscratch = R3_ARG1;
+ __ pop_i(Rindex);
+ // tos: val
+ // Rarray: array ptr (popped by index_check)
+ __ index_check(Rarray, Rindex, LogBytesPerShort, Rscratch, Rarray);
+ __ sth(R17_tos, arrayOopDesc::base_offset_in_bytes(T_CHAR), Rarray);
+}
+
+void TemplateTable::sastore() {
+ castore();
+}
+
+void TemplateTable::istore(int n) {
+ transition(itos, vtos);
+ __ stw(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::lstore(int n) {
+ transition(ltos, vtos);
+ __ std(R17_tos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
+}
+
+void TemplateTable::fstore(int n) {
+ transition(ftos, vtos);
+ __ stfs(F15_ftos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::dstore(int n) {
+ transition(dtos, vtos);
+ __ stfd(F15_ftos, Interpreter::local_offset_in_bytes(n + 1), R18_locals);
+}
+
+void TemplateTable::astore(int n) {
+ transition(vtos, vtos);
+
+ __ pop_ptr();
+ __ verify_oop_or_return_address(R17_tos, R11_scratch1);
+ __ std(R17_tos, Interpreter::local_offset_in_bytes(n), R18_locals);
+}
+
+void TemplateTable::pop() {
+ transition(vtos, vtos);
+
+ __ addi(R15_esp, R15_esp, Interpreter::stackElementSize);
+}
+
+void TemplateTable::pop2() {
+ transition(vtos, vtos);
+
+ __ addi(R15_esp, R15_esp, Interpreter::stackElementSize * 2);
+}
+
+void TemplateTable::dup() {
+ transition(vtos, vtos);
+
+ __ ld(R11_scratch1, Interpreter::stackElementSize, R15_esp);
+ __ push_ptr(R11_scratch1);
+}
+
+void TemplateTable::dup_x1() {
+ transition(vtos, vtos);
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2;
+ // stack: ..., a, b
+ __ ld(Rb, Interpreter::stackElementSize, R15_esp);
+ __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Rb, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Ra, Interpreter::stackElementSize, R15_esp);
+ __ push_ptr(Rb);
+ // stack: ..., b, a, b
+}
+
+void TemplateTable::dup_x2() {
+ transition(vtos, vtos);
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2,
+ Rc = R3_ARG1;
+
+ // stack: ..., a, b, c
+ __ ld(Rc, Interpreter::stackElementSize, R15_esp); // load c
+ __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp); // load a
+ __ std(Rc, Interpreter::stackElementSize * 3, R15_esp); // store c in a
+ __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp); // load b
+ // stack: ..., c, b, c
+ __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in b
+ // stack: ..., c, a, c
+ __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in c
+ __ push_ptr(Rc); // push c
+ // stack: ..., c, a, b, c
+}
+
+void TemplateTable::dup2() {
+ transition(vtos, vtos);
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2;
+ // stack: ..., a, b
+ __ ld(Rb, Interpreter::stackElementSize, R15_esp);
+ __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
+ __ push_2ptrs(Ra, Rb);
+ // stack: ..., a, b, a, b
+}
+
+void TemplateTable::dup2_x1() {
+ transition(vtos, vtos);
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2,
+ Rc = R3_ARG1;
+ // stack: ..., a, b, c
+ __ ld(Rc, Interpreter::stackElementSize, R15_esp);
+ __ ld(Rb, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Rc, Interpreter::stackElementSize * 2, R15_esp);
+ __ ld(Ra, Interpreter::stackElementSize * 3, R15_esp);
+ __ std(Ra, Interpreter::stackElementSize, R15_esp);
+ __ std(Rb, Interpreter::stackElementSize * 3, R15_esp);
+ // stack: ..., b, c, a
+ __ push_2ptrs(Rb, Rc);
+ // stack: ..., b, c, a, b, c
+}
+
+void TemplateTable::dup2_x2() {
+ transition(vtos, vtos);
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2,
+ Rc = R3_ARG1,
+ Rd = R4_ARG2;
+ // stack: ..., a, b, c, d
+ __ ld(Rb, Interpreter::stackElementSize * 3, R15_esp);
+ __ ld(Rd, Interpreter::stackElementSize, R15_esp);
+ __ std(Rb, Interpreter::stackElementSize, R15_esp); // store b in d
+ __ std(Rd, Interpreter::stackElementSize * 3, R15_esp); // store d in b
+ __ ld(Ra, Interpreter::stackElementSize * 4, R15_esp);
+ __ ld(Rc, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Ra, Interpreter::stackElementSize * 2, R15_esp); // store a in c
+ __ std(Rc, Interpreter::stackElementSize * 4, R15_esp); // store c in a
+ // stack: ..., c, d, a, b
+ __ push_2ptrs(Rc, Rd);
+ // stack: ..., c, d, a, b, c, d
+}
+
+void TemplateTable::swap() {
+ transition(vtos, vtos);
+ // stack: ..., a, b
+
+ Register Ra = R11_scratch1,
+ Rb = R12_scratch2;
+ // stack: ..., a, b
+ __ ld(Rb, Interpreter::stackElementSize, R15_esp);
+ __ ld(Ra, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Rb, Interpreter::stackElementSize * 2, R15_esp);
+ __ std(Ra, Interpreter::stackElementSize, R15_esp);
+ // stack: ..., b, a
+}
+
+void TemplateTable::iop2(Operation op) {
+ transition(itos, itos);
+
+ Register Rscratch = R11_scratch1;
+
+ __ pop_i(Rscratch);
+ // tos = number of bits to shift
+ // Rscratch = value to shift
+ switch (op) {
+ case add: __ add(R17_tos, Rscratch, R17_tos); break;
+ case sub: __ sub(R17_tos, Rscratch, R17_tos); break;
+ case mul: __ mullw(R17_tos, Rscratch, R17_tos); break;
+ case _and: __ andr(R17_tos, Rscratch, R17_tos); break;
+ case _or: __ orr(R17_tos, Rscratch, R17_tos); break;
+ case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break;
+ case shl: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ slw(R17_tos, Rscratch, R17_tos); break;
+ case shr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ sraw(R17_tos, Rscratch, R17_tos); break;
+ case ushr: __ rldicl(R17_tos, R17_tos, 0, 64-5); __ srw(R17_tos, Rscratch, R17_tos); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void TemplateTable::lop2(Operation op) {
+ transition(ltos, ltos);
+
+ Register Rscratch = R11_scratch1;
+ __ pop_l(Rscratch);
+ switch (op) {
+ case add: __ add(R17_tos, Rscratch, R17_tos); break;
+ case sub: __ sub(R17_tos, Rscratch, R17_tos); break;
+ case _and: __ andr(R17_tos, Rscratch, R17_tos); break;
+ case _or: __ orr(R17_tos, Rscratch, R17_tos); break;
+ case _xor: __ xorr(R17_tos, Rscratch, R17_tos); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void TemplateTable::idiv() {
+ transition(itos, itos);
+
+ Label Lnormal, Lexception, Ldone;
+ Register Rdividend = R11_scratch1; // Used by irem.
+
+ __ addi(R0, R17_tos, 1);
+ __ cmplwi(CCR0, R0, 2);
+ __ bgt(CCR0, Lnormal); // divisor <-1 or >1
+
+ __ cmpwi(CCR1, R17_tos, 0);
+ __ beq(CCR1, Lexception); // divisor == 0
+
+ __ pop_i(Rdividend);
+ __ mullw(R17_tos, Rdividend, R17_tos); // div by +/-1
+ __ b(Ldone);
+
+ __ bind(Lexception);
+ __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ __ align(32, 12);
+ __ bind(Lnormal);
+ __ pop_i(Rdividend);
+ __ divw(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1.
+ __ bind(Ldone);
+}
+
+void TemplateTable::irem() {
+ transition(itos, itos);
+
+ __ mr(R12_scratch2, R17_tos);
+ idiv();
+ __ mullw(R17_tos, R17_tos, R12_scratch2);
+ __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by idiv.
+}
+
+void TemplateTable::lmul() {
+ transition(ltos, ltos);
+
+ __ pop_l(R11_scratch1);
+ __ mulld(R17_tos, R11_scratch1, R17_tos);
+}
+
+void TemplateTable::ldiv() {
+ transition(ltos, ltos);
+
+ Label Lnormal, Lexception, Ldone;
+ Register Rdividend = R11_scratch1; // Used by lrem.
+
+ __ addi(R0, R17_tos, 1);
+ __ cmpldi(CCR0, R0, 2);
+ __ bgt(CCR0, Lnormal); // divisor <-1 or >1
+
+ __ cmpdi(CCR1, R17_tos, 0);
+ __ beq(CCR1, Lexception); // divisor == 0
+
+ __ pop_l(Rdividend);
+ __ mulld(R17_tos, Rdividend, R17_tos); // div by +/-1
+ __ b(Ldone);
+
+ __ bind(Lexception);
+ __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ArithmeticException_entry);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ __ align(32, 12);
+ __ bind(Lnormal);
+ __ pop_l(Rdividend);
+ __ divd(R17_tos, Rdividend, R17_tos); // Can't divide minint/-1.
+ __ bind(Ldone);
+}
+
+void TemplateTable::lrem() {
+ transition(ltos, ltos);
+
+ __ mr(R12_scratch2, R17_tos);
+ ldiv();
+ __ mulld(R17_tos, R17_tos, R12_scratch2);
+ __ subf(R17_tos, R17_tos, R11_scratch1); // Dividend set by ldiv.
+}
+
+void TemplateTable::lshl() {
+ transition(itos, ltos);
+
+ __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
+ __ pop_l(R11_scratch1);
+ __ sld(R17_tos, R11_scratch1, R17_tos);
+}
+
+void TemplateTable::lshr() {
+ transition(itos, ltos);
+
+ __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
+ __ pop_l(R11_scratch1);
+ __ srad(R17_tos, R11_scratch1, R17_tos);
+}
+
+void TemplateTable::lushr() {
+ transition(itos, ltos);
+
+ __ rldicl(R17_tos, R17_tos, 0, 64-6); // Extract least significant bits.
+ __ pop_l(R11_scratch1);
+ __ srd(R17_tos, R11_scratch1, R17_tos);
+}
+
+void TemplateTable::fop2(Operation op) {
+ transition(ftos, ftos);
+
+ switch (op) {
+ case add: __ pop_f(F0_SCRATCH); __ fadds(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case sub: __ pop_f(F0_SCRATCH); __ fsubs(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case mul: __ pop_f(F0_SCRATCH); __ fmuls(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case div: __ pop_f(F0_SCRATCH); __ fdivs(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case rem:
+ __ pop_f(F1_ARG1);
+ __ fmr(F2_ARG2, F15_ftos);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem));
+ __ fmr(F15_ftos, F1_RET);
+ break;
+
+ default: ShouldNotReachHere();
+ }
+}
+
+void TemplateTable::dop2(Operation op) {
+ transition(dtos, dtos);
+
+ switch (op) {
+ case add: __ pop_d(F0_SCRATCH); __ fadd(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case sub: __ pop_d(F0_SCRATCH); __ fsub(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case mul: __ pop_d(F0_SCRATCH); __ fmul(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case div: __ pop_d(F0_SCRATCH); __ fdiv(F15_ftos, F0_SCRATCH, F15_ftos); break;
+ case rem:
+ __ pop_d(F1_ARG1);
+ __ fmr(F2_ARG2, F15_ftos);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem));
+ __ fmr(F15_ftos, F1_RET);
+ break;
+
+ default: ShouldNotReachHere();
+ }
+}
+
+// Negate the value in the TOS cache.
+void TemplateTable::ineg() {
+ transition(itos, itos);
+
+ __ neg(R17_tos, R17_tos);
+}
+
+// Negate the value in the TOS cache.
+void TemplateTable::lneg() {
+ transition(ltos, ltos);
+
+ __ neg(R17_tos, R17_tos);
+}
+
+void TemplateTable::fneg() {
+ transition(ftos, ftos);
+
+ __ fneg(F15_ftos, F15_ftos);
+}
+
+void TemplateTable::dneg() {
+ transition(dtos, dtos);
+
+ __ fneg(F15_ftos, F15_ftos);
+}
+
+// Increments a local variable in place.
+void TemplateTable::iinc() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R11_scratch1,
+ Rincrement = R0,
+ Rvalue = R12_scratch2;
+
+ locals_index(Rindex); // Load locals index from bytecode stream.
+ __ lbz(Rincrement, 2, R14_bcp); // Load increment from the bytecode stream.
+ __ extsb(Rincrement, Rincrement);
+
+ __ load_local_int(Rvalue, Rindex, Rindex); // Puts address of local into Rindex.
+
+ __ add(Rvalue, Rincrement, Rvalue);
+ __ stw(Rvalue, 0, Rindex);
+}
+
+void TemplateTable::wide_iinc() {
+ transition(vtos, vtos);
+
+ Register Rindex = R11_scratch1,
+ Rlocals_addr = Rindex,
+ Rincr = R12_scratch2;
+ locals_index_wide(Rindex);
+ __ get_2_byte_integer_at_bcp(4, Rincr, InterpreterMacroAssembler::Signed);
+ __ load_local_int(R17_tos, Rlocals_addr, Rindex);
+ __ add(R17_tos, Rincr, R17_tos);
+ __ stw(R17_tos, 0, Rlocals_addr);
+}
+
+void TemplateTable::convert() {
+ // %%%%% Factor this first part accross platforms
+#ifdef ASSERT
+ TosState tos_in = ilgl;
+ TosState tos_out = ilgl;
+ switch (bytecode()) {
+ case Bytecodes::_i2l: // fall through
+ case Bytecodes::_i2f: // fall through
+ case Bytecodes::_i2d: // fall through
+ case Bytecodes::_i2b: // fall through
+ case Bytecodes::_i2c: // fall through
+ case Bytecodes::_i2s: tos_in = itos; break;
+ case Bytecodes::_l2i: // fall through
+ case Bytecodes::_l2f: // fall through
+ case Bytecodes::_l2d: tos_in = ltos; break;
+ case Bytecodes::_f2i: // fall through
+ case Bytecodes::_f2l: // fall through
+ case Bytecodes::_f2d: tos_in = ftos; break;
+ case Bytecodes::_d2i: // fall through
+ case Bytecodes::_d2l: // fall through
+ case Bytecodes::_d2f: tos_in = dtos; break;
+ default : ShouldNotReachHere();
+ }
+ switch (bytecode()) {
+ case Bytecodes::_l2i: // fall through
+ case Bytecodes::_f2i: // fall through
+ case Bytecodes::_d2i: // fall through
+ case Bytecodes::_i2b: // fall through
+ case Bytecodes::_i2c: // fall through
+ case Bytecodes::_i2s: tos_out = itos; break;
+ case Bytecodes::_i2l: // fall through
+ case Bytecodes::_f2l: // fall through
+ case Bytecodes::_d2l: tos_out = ltos; break;
+ case Bytecodes::_i2f: // fall through
+ case Bytecodes::_l2f: // fall through
+ case Bytecodes::_d2f: tos_out = ftos; break;
+ case Bytecodes::_i2d: // fall through
+ case Bytecodes::_l2d: // fall through
+ case Bytecodes::_f2d: tos_out = dtos; break;
+ default : ShouldNotReachHere();
+ }
+ transition(tos_in, tos_out);
+#endif
+
+ // Conversion
+ Label done;
+ switch (bytecode()) {
+ case Bytecodes::_i2l:
+ __ extsw(R17_tos, R17_tos);
+ break;
+
+ case Bytecodes::_l2i:
+ // Nothing to do, we'll continue to work with the lower bits.
+ break;
+
+ case Bytecodes::_i2b:
+ __ extsb(R17_tos, R17_tos);
+ break;
+
+ case Bytecodes::_i2c:
+ __ rldicl(R17_tos, R17_tos, 0, 64-2*8);
+ break;
+
+ case Bytecodes::_i2s:
+ __ extsh(R17_tos, R17_tos);
+ break;
+
+ case Bytecodes::_i2d:
+ __ extsw(R17_tos, R17_tos);
+ case Bytecodes::_l2d:
+ __ push_l_pop_d();
+ __ fcfid(F15_ftos, F15_ftos);
+ break;
+
+ case Bytecodes::_i2f:
+ __ extsw(R17_tos, R17_tos);
+ __ push_l_pop_d();
+ if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only
+ // Comment: alternatively, load with sign extend could be done by lfiwax.
+ __ fcfids(F15_ftos, F15_ftos);
+ } else {
+ __ fcfid(F15_ftos, F15_ftos);
+ __ frsp(F15_ftos, F15_ftos);
+ }
+ break;
+
+ case Bytecodes::_l2f:
+ if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only
+ __ push_l_pop_d();
+ __ fcfids(F15_ftos, F15_ftos);
+ } else {
+ // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp.
+ __ mr(R3_ARG1, R17_tos);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f));
+ __ fmr(F15_ftos, F1_RET);
+ }
+ break;
+
+ case Bytecodes::_f2d:
+ // empty
+ break;
+
+ case Bytecodes::_d2f:
+ __ frsp(F15_ftos, F15_ftos);
+ break;
+
+ case Bytecodes::_d2i:
+ case Bytecodes::_f2i:
+ __ fcmpu(CCR0, F15_ftos, F15_ftos);
+ __ li(R17_tos, 0); // 0 in case of NAN
+ __ bso(CCR0, done);
+ __ fctiwz(F15_ftos, F15_ftos);
+ __ push_d_pop_l();
+ break;
+
+ case Bytecodes::_d2l:
+ case Bytecodes::_f2l:
+ __ fcmpu(CCR0, F15_ftos, F15_ftos);
+ __ li(R17_tos, 0); // 0 in case of NAN
+ __ bso(CCR0, done);
+ __ fctidz(F15_ftos, F15_ftos);
+ __ push_d_pop_l();
+ break;
+
+ default: ShouldNotReachHere();
+ }
+ __ bind(done);
+}
+
+// Long compare
+void TemplateTable::lcmp() {
+ transition(ltos, itos);
+
+ const Register Rscratch = R11_scratch1;
+ __ pop_l(Rscratch); // first operand, deeper in stack
+
+ __ cmpd(CCR0, Rscratch, R17_tos); // compare
+ __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01
+ __ srwi(Rscratch, R17_tos, 30);
+ __ srawi(R17_tos, R17_tos, 31);
+ __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1
+}
+
+// fcmpl/fcmpg and dcmpl/dcmpg bytecodes
+// unordered_result == -1 => fcmpl or dcmpl
+// unordered_result == 1 => fcmpg or dcmpg
+void TemplateTable::float_cmp(bool is_float, int unordered_result) {
+ const FloatRegister Rfirst = F0_SCRATCH,
+ Rsecond = F15_ftos;
+ const Register Rscratch = R11_scratch1;
+
+ if (is_float) {
+ __ pop_f(Rfirst);
+ } else {
+ __ pop_d(Rfirst);
+ }
+
+ Label Lunordered, Ldone;
+ __ fcmpu(CCR0, Rfirst, Rsecond); // compare
+ if (unordered_result) {
+ __ bso(CCR0, Lunordered);
+ }
+ __ mfcr(R17_tos); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01
+ __ srwi(Rscratch, R17_tos, 30);
+ __ srawi(R17_tos, R17_tos, 31);
+ __ orr(R17_tos, Rscratch, R17_tos); // set result as follows: <: -1, =: 0, >: 1
+ if (unordered_result) {
+ __ b(Ldone);
+ __ bind(Lunordered);
+ __ load_const_optimized(R17_tos, unordered_result);
+ }
+ __ bind(Ldone);
+}
+
+// Branch_conditional which takes TemplateTable::Condition.
+void TemplateTable::branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert) {
+ bool positive = false;
+ Assembler::Condition cond = Assembler::equal;
+ switch (cc) {
+ case TemplateTable::equal: positive = true ; cond = Assembler::equal ; break;
+ case TemplateTable::not_equal: positive = false; cond = Assembler::equal ; break;
+ case TemplateTable::less: positive = true ; cond = Assembler::less ; break;
+ case TemplateTable::less_equal: positive = false; cond = Assembler::greater; break;
+ case TemplateTable::greater: positive = true ; cond = Assembler::greater; break;
+ case TemplateTable::greater_equal: positive = false; cond = Assembler::less ; break;
+ default: ShouldNotReachHere();
+ }
+ int bo = (positive != invert) ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0;
+ int bi = Assembler::bi0(crx, cond);
+ __ bc(bo, bi, L);
+}
+
+void TemplateTable::branch(bool is_jsr, bool is_wide) {
+
+ // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also.
+ __ verify_thread();
+
+ const Register Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rscratch3 = R3_ARG1,
+ R4_counters = R4_ARG2,
+ bumped_count = R31,
+ Rdisp = R22_tmp2;
+
+ __ profile_taken_branch(Rscratch1, bumped_count);
+
+ // Get (wide) offset.
+ if (is_wide) {
+ __ get_4_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed);
+ } else {
+ __ get_2_byte_integer_at_bcp(1, Rdisp, InterpreterMacroAssembler::Signed);
+ }
+
+ // --------------------------------------------------------------------------
+ // Handle all the JSR stuff here, then exit.
+ // It's much shorter and cleaner than intermingling with the
+ // non-JSR normal-branch stuff occurring below.
+ if (is_jsr) {
+ // Compute return address as bci in Otos_i.
+ __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method);
+ __ addi(Rscratch2, R14_bcp, -in_bytes(ConstMethod::codes_offset()) + (is_wide ? 5 : 3));
+ __ subf(R17_tos, Rscratch1, Rscratch2);
+
+ // Bump bcp to target of JSR.
+ __ add(R14_bcp, Rdisp, R14_bcp);
+ // Push returnAddress for "ret" on stack.
+ __ push_ptr(R17_tos);
+ // And away we go!
+ __ dispatch_next(vtos);
+ return;
+ }
+
+ // --------------------------------------------------------------------------
+ // Normal (non-jsr) branch handling
+
+ const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter;
+ if (increment_invocation_counter_for_backward_branches) {
+ //__ unimplemented("branch invocation counter");
+
+ Label Lforward;
+ __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.
+
+ // Check branch direction.
+ __ cmpdi(CCR0, Rdisp, 0);
+ __ bgt(CCR0, Lforward);
+
+ __ get_method_counters(R19_method, R4_counters, Lforward);
+
+ if (TieredCompilation) {
+ Label Lno_mdo, Loverflow;
+ const int increment = InvocationCounter::count_increment;
+ const int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift;
+ if (ProfileInterpreter) {
+ Register Rmdo = Rscratch1;
+
+ // If no method data exists, go to profile_continue.
+ __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method);
+ __ cmpdi(CCR0, Rmdo, 0);
+ __ beq(CCR0, Lno_mdo);
+
+ // Increment backedge counter in the MDO.
+ const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ lwz(Rscratch2, mdo_bc_offs, Rmdo);
+ __ load_const_optimized(Rscratch3, mask, R0);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mdo_bc_offs, Rmdo);
+ __ and_(Rscratch3, Rscratch2, Rscratch3);
+ __ bne(CCR0, Lforward);
+ __ b(Loverflow);
+ }
+
+ // If there's no MDO, increment counter in method.
+ const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset());
+ __ bind(Lno_mdo);
+ __ lwz(Rscratch2, mo_bc_offs, R4_counters);
+ __ load_const_optimized(Rscratch3, mask, R0);
+ __ addi(Rscratch2, Rscratch2, increment);
+ __ stw(Rscratch2, mo_bc_offs, R19_method);
+ __ and_(Rscratch3, Rscratch2, Rscratch3);
+ __ bne(CCR0, Lforward);
+
+ __ bind(Loverflow);
+
+ // Notify point for loop, pass branch bytecode.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R14_bcp, true);
+
+ // Was an OSR adapter generated?
+ // O0 = osr nmethod
+ __ cmpdi(CCR0, R3_RET, 0);
+ __ beq(CCR0, Lforward);
+
+ // Has the nmethod been invalidated already?
+ __ lwz(R0, nmethod::entry_bci_offset(), R3_RET);
+ __ cmpwi(CCR0, R0, InvalidOSREntryBci);
+ __ beq(CCR0, Lforward);
+
+ // Migrate the interpreter frame off of the stack.
+ // We can use all registers because we will not return to interpreter from this point.
+
+ // Save nmethod.
+ const Register osr_nmethod = R31;
+ __ mr(osr_nmethod, R3_RET);
+ __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread);
+ __ reset_last_Java_frame();
+ // OSR buffer is in ARG1.
+
+ // Remove the interpreter frame.
+ __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2);
+
+ // Jump to the osr code.
+ __ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod);
+ __ mtlr(R0);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ } else {
+
+ const Register invoke_ctr = Rscratch1;
+ // Update Backedge branch separately from invocations.
+ __ increment_backedge_counter(R4_counters, invoke_ctr, Rscratch2, Rscratch3);
+
+ if (ProfileInterpreter) {
+ __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward);
+ if (UseOnStackReplacement) {
+ __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2);
+ }
+ } else {
+ if (UseOnStackReplacement) {
+ __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2);
+ }
+ }
+ }
+
+ __ bind(Lforward);
+
+ } else {
+ // Bump bytecode pointer by displacement (take the branch).
+ __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr.
+ }
+ // Continue with bytecode @ target.
+ // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above,
+ // %%%%% and changing dispatch_next to dispatch_only.
+ __ dispatch_next(vtos);
+}
+
+// Helper function for if_cmp* methods below.
+// Factored out common compare and branch code.
+void TemplateTable::if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0) {
+ Label Lnot_taken;
+ // Note: The condition code we get is the condition under which we
+ // *fall through*! So we have to inverse the CC here.
+
+ if (is_jint) {
+ if (cmp0) {
+ __ cmpwi(CCR0, Rfirst, 0);
+ } else {
+ __ cmpw(CCR0, Rfirst, Rsecond);
+ }
+ } else {
+ if (cmp0) {
+ __ cmpdi(CCR0, Rfirst, 0);
+ } else {
+ __ cmpd(CCR0, Rfirst, Rsecond);
+ }
+ }
+ branch_conditional(CCR0, cc, Lnot_taken, /*invert*/ true);
+
+ // Conition is false => Jump!
+ branch(false, false);
+
+ // Condition is not true => Continue.
+ __ align(32, 12);
+ __ bind(Lnot_taken);
+ __ profile_not_taken_branch(Rscratch1, Rscratch2);
+}
+
+// Compare integer values with zero and fall through if CC holds, branch away otherwise.
+void TemplateTable::if_0cmp(Condition cc) {
+ transition(itos, vtos);
+
+ if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, true, true);
+}
+
+// Compare integer values and fall through if CC holds, branch away otherwise.
+//
+// Interface:
+// - Rfirst: First operand (older stack value)
+// - tos: Second operand (younger stack value)
+void TemplateTable::if_icmp(Condition cc) {
+ transition(itos, vtos);
+
+ const Register Rfirst = R0,
+ Rsecond = R17_tos;
+
+ __ pop_i(Rfirst);
+ if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, true, false);
+}
+
+void TemplateTable::if_nullcmp(Condition cc) {
+ transition(atos, vtos);
+
+ if_cmp_common(R17_tos, noreg, R11_scratch1, R12_scratch2, cc, false, true);
+}
+
+void TemplateTable::if_acmp(Condition cc) {
+ transition(atos, vtos);
+
+ const Register Rfirst = R0,
+ Rsecond = R17_tos;
+
+ __ pop_ptr(Rfirst);
+ if_cmp_common(Rfirst, Rsecond, R11_scratch1, R12_scratch2, cc, false, false);
+}
+
+void TemplateTable::ret() {
+ locals_index(R11_scratch1);
+ __ load_local_ptr(R17_tos, R11_scratch1, R11_scratch1);
+
+ __ profile_ret(vtos, R17_tos, R11_scratch1, R12_scratch2);
+
+ __ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
+ __ add(R11_scratch1, R17_tos, R11_scratch1);
+ __ addi(R14_bcp, R11_scratch1, in_bytes(ConstMethod::codes_offset()));
+ __ dispatch_next(vtos);
+}
+
+void TemplateTable::wide_ret() {
+ transition(vtos, vtos);
+
+ const Register Rindex = R3_ARG1,
+ Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2;
+
+ locals_index_wide(Rindex);
+ __ load_local_ptr(R17_tos, R17_tos, Rindex);
+ __ profile_ret(vtos, R17_tos, Rscratch1, R12_scratch2);
+ // Tos now contains the bci, compute the bcp from that.
+ __ ld(Rscratch1, in_bytes(Method::const_offset()), R19_method);
+ __ addi(Rscratch2, R17_tos, in_bytes(ConstMethod::codes_offset()));
+ __ add(R14_bcp, Rscratch1, Rscratch2);
+ __ dispatch_next(vtos);
+}
+
+void TemplateTable::tableswitch() {
+ transition(itos, vtos);
+
+ Label Ldispatch, Ldefault_case;
+ Register Rlow_byte = R3_ARG1,
+ Rindex = Rlow_byte,
+ Rhigh_byte = R4_ARG2,
+ Rdef_offset_addr = R5_ARG3, // is going to contain address of default offset
+ Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Roffset = R6_ARG4;
+
+ // Align bcp.
+ __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
+ __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt));
+
+ // Load lo & hi.
+ __ lwz(Rlow_byte, BytesPerInt, Rdef_offset_addr);
+ __ lwz(Rhigh_byte, BytesPerInt * 2, Rdef_offset_addr);
+
+ // Check for default case (=index outside [low,high]).
+ __ cmpw(CCR0, R17_tos, Rlow_byte);
+ __ cmpw(CCR1, R17_tos, Rhigh_byte);
+ __ blt(CCR0, Ldefault_case);
+ __ bgt(CCR1, Ldefault_case);
+
+ // Lookup dispatch offset.
+ __ sub(Rindex, R17_tos, Rlow_byte);
+ __ extsw(Rindex, Rindex);
+ __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2);
+ __ sldi(Rindex, Rindex, LogBytesPerInt);
+ __ addi(Rindex, Rindex, 3 * BytesPerInt);
+ __ lwax(Roffset, Rdef_offset_addr, Rindex);
+ __ b(Ldispatch);
+
+ __ bind(Ldefault_case);
+ __ profile_switch_default(Rhigh_byte, Rscratch1);
+ __ lwa(Roffset, 0, Rdef_offset_addr);
+
+ __ bind(Ldispatch);
+
+ __ add(R14_bcp, Roffset, R14_bcp);
+ __ dispatch_next(vtos);
+}
+
+void TemplateTable::lookupswitch() {
+ transition(itos, itos);
+ __ stop("lookupswitch bytecode should have been rewritten");
+}
+
+// Table switch using linear search through cases.
+// Bytecode stream format:
+// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ...
+// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value.
+void TemplateTable::fast_linearswitch() {
+ transition(itos, vtos);
+
+ Label Lloop_entry, Lsearch_loop, Lfound, Lcontinue_execution, Ldefault_case;
+
+ Register Rcount = R3_ARG1,
+ Rcurrent_pair = R4_ARG2,
+ Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset.
+ Roffset = R31, // Might need to survive C call.
+ Rvalue = R12_scratch2,
+ Rscratch = R11_scratch1,
+ Rcmp_value = R17_tos;
+
+ // Align bcp.
+ __ addi(Rdef_offset_addr, R14_bcp, BytesPerInt);
+ __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt));
+
+ // Setup loop counter and limit.
+ __ lwz(Rcount, BytesPerInt, Rdef_offset_addr); // Load count.
+ __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair.
+
+ // Set up search loop.
+ __ cmpwi(CCR0, Rcount, 0);
+ __ beq(CCR0, Ldefault_case);
+
+ __ mtctr(Rcount);
+
+ // linear table search
+ __ bind(Lsearch_loop);
+
+ __ lwz(Rvalue, 0, Rcurrent_pair);
+ __ lwa(Roffset, 1 * BytesPerInt, Rcurrent_pair);
+
+ __ cmpw(CCR0, Rvalue, Rcmp_value);
+ __ beq(CCR0, Lfound);
+
+ __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt);
+ __ bdnz(Lsearch_loop);
+
+ // default case
+ __ bind(Ldefault_case);
+
+ __ lwa(Roffset, 0, Rdef_offset_addr);
+ if (ProfileInterpreter) {
+ __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */);
+ __ b(Lcontinue_execution);
+ }
+
+ // Entry found, skip Roffset bytecodes and continue.
+ __ bind(Lfound);
+ if (ProfileInterpreter) {
+ // Calc the num of the pair we hit. Careful, Rcurrent_pair points 2 ints
+ // beyond the actual current pair due to the auto update load above!
+ __ sub(Rcurrent_pair, Rcurrent_pair, Rdef_offset_addr);
+ __ addi(Rcurrent_pair, Rcurrent_pair, - 2 * BytesPerInt);
+ __ srdi(Rcurrent_pair, Rcurrent_pair, LogBytesPerInt + 1);
+ __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch);
+ __ bind(Lcontinue_execution);
+ }
+ __ add(R14_bcp, Roffset, R14_bcp);
+ __ dispatch_next(vtos);
+}
+
+// Table switch using binary search (value/offset pairs are ordered).
+// Bytecode stream format:
+// Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ...
+// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value.
+void TemplateTable::fast_binaryswitch() {
+
+ transition(itos, vtos);
+ // Implementation using the following core algorithm: (copied from Intel)
+ //
+ // int binary_search(int key, LookupswitchPair* array, int n) {
+ // // Binary search according to "Methodik des Programmierens" by
+ // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985.
+ // int i = 0;
+ // int j = n;
+ // while (i+1 < j) {
+ // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q)
+ // // with Q: for all i: 0 <= i < n: key < a[i]
+ // // where a stands for the array and assuming that the (inexisting)
+ // // element a[n] is infinitely big.
+ // int h = (i + j) >> 1;
+ // // i < h < j
+ // if (key < array[h].fast_match()) {
+ // j = h;
+ // } else {
+ // i = h;
+ // }
+ // }
+ // // R: a[i] <= key < a[i+1] or Q
+ // // (i.e., if key is within array, i is the correct index)
+ // return i;
+ // }
+
+ // register allocation
+ const Register Rkey = R17_tos; // already set (tosca)
+ const Register Rarray = R3_ARG1;
+ const Register Ri = R4_ARG2;
+ const Register Rj = R5_ARG3;
+ const Register Rh = R6_ARG4;
+ const Register Rscratch = R11_scratch1;
+
+ const int log_entry_size = 3;
+ const int entry_size = 1 << log_entry_size;
+
+ Label found;
+
+ // Find Array start,
+ __ addi(Rarray, R14_bcp, 3 * BytesPerInt);
+ __ clrrdi(Rarray, Rarray, log2_long((jlong)BytesPerInt));
+
+ // initialize i & j
+ __ li(Ri,0);
+ __ lwz(Rj, -BytesPerInt, Rarray);
+
+ // and start.
+ Label entry;
+ __ b(entry);
+
+ // binary search loop
+ { Label loop;
+ __ bind(loop);
+ // int h = (i + j) >> 1;
+ __ srdi(Rh, Rh, 1);
+ // if (key < array[h].fast_match()) {
+ // j = h;
+ // } else {
+ // i = h;
+ // }
+ __ sldi(Rscratch, Rh, log_entry_size);
+ __ lwzx(Rscratch, Rscratch, Rarray);
+
+ // if (key < current value)
+ // Rh = Rj
+ // else
+ // Rh = Ri
+ Label Lgreater;
+ __ cmpw(CCR0, Rkey, Rscratch);
+ __ bge(CCR0, Lgreater);
+ __ mr(Rj, Rh);
+ __ b(entry);
+ __ bind(Lgreater);
+ __ mr(Ri, Rh);
+
+ // while (i+1 < j)
+ __ bind(entry);
+ __ addi(Rscratch, Ri, 1);
+ __ cmpw(CCR0, Rscratch, Rj);
+ __ add(Rh, Ri, Rj); // start h = i + j >> 1;
+
+ __ blt(CCR0, loop);
+ }
+
+ // End of binary search, result index is i (must check again!).
+ Label default_case;
+ Label continue_execution;
+ if (ProfileInterpreter) {
+ __ mr(Rh, Ri); // Save index in i for profiling.
+ }
+ // Ri = value offset
+ __ sldi(Ri, Ri, log_entry_size);
+ __ add(Ri, Ri, Rarray);
+ __ lwz(Rscratch, 0, Ri);
+
+ Label not_found;
+ // Ri = offset offset
+ __ cmpw(CCR0, Rkey, Rscratch);
+ __ beq(CCR0, not_found);
+ // entry not found -> j = default offset
+ __ lwz(Rj, -2 * BytesPerInt, Rarray);
+ __ b(default_case);
+
+ __ bind(not_found);
+ // entry found -> j = offset
+ __ profile_switch_case(Rh, Rj, Rscratch, Rkey);
+ __ lwz(Rj, BytesPerInt, Ri);
+
+ if (ProfileInterpreter) {
+ __ b(continue_execution);
+ }
+
+ __ bind(default_case); // fall through (if not profiling)
+ __ profile_switch_default(Ri, Rscratch);
+
+ __ bind(continue_execution);
+
+ __ extsw(Rj, Rj);
+ __ add(R14_bcp, Rj, R14_bcp);
+ __ dispatch_next(vtos);
+}
+
+void TemplateTable::_return(TosState state) {
+ transition(state, state);
+ assert(_desc->calls_vm(),
+ "inconsistent calls_vm information"); // call in remove_activation
+
+ if (_desc->bytecode() == Bytecodes::_return_register_finalizer) {
+
+ Register Rscratch = R11_scratch1,
+ Rklass = R12_scratch2,
+ Rklass_flags = Rklass;
+ Label Lskip_register_finalizer;
+
+ // Check if the method has the FINALIZER flag set and call into the VM to finalize in this case.
+ assert(state == vtos, "only valid state");
+ __ ld(R17_tos, 0, R18_locals);
+
+ // Load klass of this obj.
+ __ load_klass(Rklass, R17_tos);
+ __ lwz(Rklass_flags, in_bytes(Klass::access_flags_offset()), Rklass);
+ __ testbitdi(CCR0, R0, Rklass_flags, exact_log2(JVM_ACC_HAS_FINALIZER));
+ __ bfalse(CCR0, Lskip_register_finalizer);
+
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), R17_tos /* obj */);
+
+ __ align(32, 12);
+ __ bind(Lskip_register_finalizer);
+ }
+
+ // Move the result value into the correct register and remove memory stack frame.
+ __ remove_activation(state, /* throw_monitor_exception */ true);
+ // Restoration of lr done by remove_activation.
+ switch (state) {
+ case ltos:
+ case btos:
+ case ctos:
+ case stos:
+ case atos:
+ case itos: __ mr(R3_RET, R17_tos); break;
+ case ftos:
+ case dtos: __ fmr(F1_RET, F15_ftos); break;
+ case vtos: // This might be a constructor. Final fields (and volatile fields on PPC64) need
+ // to get visible before the reference to the object gets stored anywhere.
+ __ membar(Assembler::StoreStore); break;
+ default : ShouldNotReachHere();
+ }
+ __ blr();
+}
+
+// ============================================================================
+// Constant pool cache access
+//
+// Memory ordering:
+//
+// Like done in C++ interpreter, we load the fields
+// - _indices
+// - _f12_oop
+// acquired, because these are asked if the cache is already resolved. We don't
+// want to float loads above this check.
+// See also comments in ConstantPoolCacheEntry::bytecode_1(),
+// ConstantPoolCacheEntry::bytecode_2() and ConstantPoolCacheEntry::f1();
+
+// Call into the VM if call site is not yet resolved
+//
+// Input regs:
+// - None, all passed regs are outputs.
+//
+// Returns:
+// - Rcache: The const pool cache entry that contains the resolved result.
+// - Rresult: Either noreg or output for f1/f2.
+//
+// Kills:
+// - Rscratch
+void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Register Rscratch, size_t index_size) {
+
+ __ get_cache_and_index_at_bcp(Rcache, 1, index_size);
+ Label Lresolved, Ldone;
+
+ assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
+ // We are resolved if the indices offset contains the current bytecode.
+ // Big Endian:
+ __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache);
+ // Acquire by cmp-br-isync (see below).
+ __ cmpdi(CCR0, Rscratch, (int)bytecode());
+ __ beq(CCR0, Lresolved);
+
+ address entry = NULL;
+ switch (bytecode()) {
+ case Bytecodes::_getstatic : // fall through
+ case Bytecodes::_putstatic : // fall through
+ case Bytecodes::_getfield : // fall through
+ case Bytecodes::_putfield : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_get_put); break;
+ case Bytecodes::_invokevirtual : // fall through
+ case Bytecodes::_invokespecial : // fall through
+ case Bytecodes::_invokestatic : // fall through
+ case Bytecodes::_invokeinterface: entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invoke); break;
+ case Bytecodes::_invokehandle : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokehandle); break;
+ case Bytecodes::_invokedynamic : entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_invokedynamic); break;
+ default : ShouldNotReachHere(); break;
+ }
+ __ li(R4_ARG2, (int)bytecode());
+ __ call_VM(noreg, entry, R4_ARG2, true);
+
+ // Update registers with resolved info.
+ __ get_cache_and_index_at_bcp(Rcache, 1, index_size);
+ __ b(Ldone);
+
+ __ bind(Lresolved);
+ __ isync(); // Order load wrt. succeeding loads.
+ __ bind(Ldone);
+}
+
+// Load the constant pool cache entry at field accesses into registers.
+// The Rcache and Rindex registers must be set before call.
+// Input:
+// - Rcache, Rindex
+// Output:
+// - Robj, Roffset, Rflags
+void TemplateTable::load_field_cp_cache_entry(Register Robj,
+ Register Rcache,
+ Register Rindex /* unused on PPC64 */,
+ Register Roffset,
+ Register Rflags,
+ bool is_static = false) {
+ assert_different_registers(Rcache, Rflags, Roffset);
+ // assert(Rindex == noreg, "parameter not used on PPC64");
+
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+ __ ld(Rflags, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache);
+ __ ld(Roffset, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f2_offset()), Rcache);
+ if (is_static) {
+ __ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache);
+ __ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj);
+ // Acquire not needed here. Following access has an address dependency on this value.
+ }
+}
+
+// Load the constant pool cache entry at invokes into registers.
+// Resolve if necessary.
+
+// Input Registers:
+// - None, bcp is used, though
+//
+// Return registers:
+// - Rmethod (f1 field or f2 if invokevirtual)
+// - Ritable_index (f2 field)
+// - Rflags (flags field)
+//
+// Kills:
+// - R21
+//
+void TemplateTable::load_invoke_cp_cache_entry(int byte_no,
+ Register Rmethod,
+ Register Ritable_index,
+ Register Rflags,
+ bool is_invokevirtual,
+ bool is_invokevfinal,
+ bool is_invokedynamic) {
+
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+ // Determine constant pool cache field offsets.
+ assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant");
+ const int method_offset = in_bytes(cp_base_offset + (is_invokevirtual ? ConstantPoolCacheEntry::f2_offset() : ConstantPoolCacheEntry::f1_offset()));
+ const int flags_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::flags_offset());
+ // Access constant pool cache fields.
+ const int index_offset = in_bytes(cp_base_offset + ConstantPoolCacheEntry::f2_offset());
+
+ Register Rcache = R21_tmp1; // Note: same register as R21_sender_SP.
+
+ if (is_invokevfinal) {
+ assert(Ritable_index == noreg, "register not used");
+ // Already resolved.
+ __ get_cache_and_index_at_bcp(Rcache, 1);
+ } else {
+ resolve_cache_and_index(byte_no, Rcache, R0, is_invokedynamic ? sizeof(u4) : sizeof(u2));
+ }
+
+ __ ld(Rmethod, method_offset, Rcache);
+ __ ld(Rflags, flags_offset, Rcache);
+
+ if (Ritable_index != noreg) {
+ __ ld(Ritable_index, index_offset, Rcache);
+ }
+}
+
+// ============================================================================
+// Field access
+
+// Volatile variables demand their effects be made known to all CPU's
+// in order. Store buffers on most chips allow reads & writes to
+// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode
+// without some kind of memory barrier (i.e., it's not sufficient that
+// the interpreter does not reorder volatile references, the hardware
+// also must not reorder them).
+//
+// According to the new Java Memory Model (JMM):
+// (1) All volatiles are serialized wrt to each other. ALSO reads &
+// writes act as aquire & release, so:
+// (2) A read cannot let unrelated NON-volatile memory refs that
+// happen after the read float up to before the read. It's OK for
+// non-volatile memory refs that happen before the volatile read to
+// float down below it.
+// (3) Similar a volatile write cannot let unrelated NON-volatile
+// memory refs that happen BEFORE the write float down to after the
+// write. It's OK for non-volatile memory refs that happen after the
+// volatile write to float up before it.
+//
+// We only put in barriers around volatile refs (they are expensive),
+// not _between_ memory refs (that would require us to track the
+// flavor of the previous memory refs). Requirements (2) and (3)
+// require some barriers before volatile stores and after volatile
+// loads. These nearly cover requirement (1) but miss the
+// volatile-store-volatile-load case. This final case is placed after
+// volatile-stores although it could just as well go before
+// volatile-loads.
+
+// The registers cache and index expected to be set before call.
+// Correct values of the cache and index registers are preserved.
+// Kills:
+// Rcache (if has_tos)
+// Rscratch
+void TemplateTable::jvmti_post_field_access(Register Rcache, Register Rscratch, bool is_static, bool has_tos) {
+
+ assert_different_registers(Rcache, Rscratch);
+
+ if (JvmtiExport::can_post_field_access()) {
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+ Label Lno_field_access_post;
+
+ // Check if post field access in enabled.
+ int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_access_count_addr(), R0, true);
+ __ lwz(Rscratch, offs, Rscratch);
+
+ __ cmpwi(CCR0, Rscratch, 0);
+ __ beq(CCR0, Lno_field_access_post);
+
+ // Post access enabled - do it!
+ __ addi(Rcache, Rcache, in_bytes(cp_base_offset));
+ if (is_static) {
+ __ li(R17_tos, 0);
+ } else {
+ if (has_tos) {
+ // The fast bytecode versions have obj ptr in register.
+ // Thus, save object pointer before call_VM() clobbers it
+ // put object on tos where GC wants it.
+ __ push_ptr(R17_tos);
+ } else {
+ // Load top of stack (do not pop the value off the stack).
+ __ ld(R17_tos, Interpreter::expr_offset_in_bytes(0), R15_esp);
+ }
+ __ verify_oop(R17_tos);
+ }
+ // tos: object pointer or NULL if static
+ // cache: cache entry pointer
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), R17_tos, Rcache);
+ if (!is_static && has_tos) {
+ // Restore object pointer.
+ __ pop_ptr(R17_tos);
+ __ verify_oop(R17_tos);
+ } else {
+ // Cache is still needed to get class or obj.
+ __ get_cache_and_index_at_bcp(Rcache, 1);
+ }
+
+ __ align(32, 12);
+ __ bind(Lno_field_access_post);
+ }
+}
+
+// kills R11_scratch1
+void TemplateTable::pop_and_check_object(Register Roop) {
+ Register Rtmp = R11_scratch1;
+
+ assert_different_registers(Rtmp, Roop);
+ __ pop_ptr(Roop);
+ // For field access must check obj.
+ __ null_check_throw(Roop, -1, Rtmp);
+ __ verify_oop(Roop);
+}
+
+// PPC64: implement volatile loads as fence-store-acquire.
+void TemplateTable::getfield_or_static(int byte_no, bool is_static) {
+ transition(vtos, vtos);
+
+ Label Lacquire, Lisync;
+
+ const Register Rcache = R3_ARG1,
+ Rclass_or_obj = R22_tmp2,
+ Roffset = R23_tmp3,
+ Rflags = R31,
+ Rbtable = R5_ARG3,
+ Rbc = R6_ARG4,
+ Rscratch = R12_scratch2;
+
+ static address field_branch_table[number_of_states],
+ static_branch_table[number_of_states];
+
+ address* branch_table = is_static ? static_branch_table : field_branch_table;
+
+ // Get field offset.
+ resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2));
+
+ // JVMTI support
+ jvmti_post_field_access(Rcache, Rscratch, is_static, false);
+
+ // Load after possible GC.
+ load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static);
+
+ // Load pointer to branch table.
+ __ load_const_optimized(Rbtable, (address)branch_table, Rscratch);
+
+ // Get volatile flag.
+ __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit.
+ // Note: sync is needed before volatile load on PPC64.
+
+ // Check field type.
+ __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+
+#ifdef ASSERT
+ Label LFlagInvalid;
+ __ cmpldi(CCR0, Rflags, number_of_states);
+ __ bge(CCR0, LFlagInvalid);
+#endif
+
+ // Load from branch table and dispatch (volatile case: one instruction ahead).
+ __ sldi(Rflags, Rflags, LogBytesPerWord);
+ __ cmpwi(CCR6, Rscratch, 1); // Volatile?
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile ? size of 1 instruction : 0.
+ }
+ __ ldx(Rbtable, Rbtable, Rflags);
+
+ // Get the obj from stack.
+ if (!is_static) {
+ pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1.
+ } else {
+ __ verify_oop(Rclass_or_obj);
+ }
+
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point.
+ }
+ __ mtctr(Rbtable);
+ __ bctr();
+
+#ifdef ASSERT
+ __ bind(LFlagInvalid);
+ __ stop("got invalid flag", 0x654);
+
+ // __ bind(Lvtos);
+ address pc_before_fence = __ pc();
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(__ pc() - pc_before_fence == (ptrdiff_t)BytesPerInstWord, "must be single instruction");
+ assert(branch_table[vtos] == 0, "can't compute twice");
+ branch_table[vtos] = __ pc(); // non-volatile_entry point
+ __ stop("vtos unexpected", 0x655);
+#endif
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Ldtos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[dtos] == 0, "can't compute twice");
+ branch_table[dtos] = __ pc(); // non-volatile_entry point
+ __ lfdx(F15_ftos, Rclass_or_obj, Roffset);
+ __ push(dtos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_dgetfield, Rbc, Rscratch);
+ {
+ Label acquire_double;
+ __ beq(CCR6, acquire_double); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ bind(acquire_double);
+ __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync.
+ __ beq_predict_taken(CCR0, Lisync);
+ __ b(Lisync); // In case of NAN.
+ }
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Lftos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ftos] == 0, "can't compute twice");
+ branch_table[ftos] = __ pc(); // non-volatile_entry point
+ __ lfsx(F15_ftos, Rclass_or_obj, Roffset);
+ __ push(ftos);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_fgetfield, Rbc, Rscratch); }
+ {
+ Label acquire_float;
+ __ beq(CCR6, acquire_float); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ bind(acquire_float);
+ __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync.
+ __ beq_predict_taken(CCR0, Lisync);
+ __ b(Lisync); // In case of NAN.
+ }
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Litos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[itos] == 0, "can't compute twice");
+ branch_table[itos] = __ pc(); // non-volatile_entry point
+ __ lwax(R17_tos, Rclass_or_obj, Roffset);
+ __ push(itos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_igetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Lltos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ltos] == 0, "can't compute twice");
+ branch_table[ltos] = __ pc(); // non-volatile_entry point
+ __ ldx(R17_tos, Rclass_or_obj, Roffset);
+ __ push(ltos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_lgetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Lbtos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[btos] == 0, "can't compute twice");
+ branch_table[btos] = __ pc(); // non-volatile_entry point
+ __ lbzx(R17_tos, Rclass_or_obj, Roffset);
+ __ extsb(R17_tos, R17_tos);
+ __ push(btos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_bgetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Lctos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ctos] == 0, "can't compute twice");
+ branch_table[ctos] = __ pc(); // non-volatile_entry point
+ __ lhzx(R17_tos, Rclass_or_obj, Roffset);
+ __ push(ctos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_cgetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Lstos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[stos] == 0, "can't compute twice");
+ branch_table[stos] = __ pc(); // non-volatile_entry point
+ __ lhax(R17_tos, Rclass_or_obj, Roffset);
+ __ push(stos);
+ if (!is_static) patch_bytecode(Bytecodes::_fast_sgetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align load.
+ // __ bind(Latos);
+ __ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[atos] == 0, "can't compute twice");
+ branch_table[atos] = __ pc(); // non-volatile_entry point
+ __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ __ verify_oop(R17_tos);
+ __ push(atos);
+ //__ dcbt(R17_tos); // prefetch
+ if (!is_static) patch_bytecode(Bytecodes::_fast_agetfield, Rbc, Rscratch);
+ __ beq(CCR6, Lacquire); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 12);
+ __ bind(Lacquire);
+ __ twi_0(R17_tos);
+ __ bind(Lisync);
+ __ isync(); // acquire
+
+#ifdef ASSERT
+ for (int i = 0; iprint_cr("get: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)",
+ // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i]));
+ }
+#endif
+}
+
+void TemplateTable::getfield(int byte_no) {
+ getfield_or_static(byte_no, false);
+}
+
+void TemplateTable::getstatic(int byte_no) {
+ getfield_or_static(byte_no, true);
+}
+
+// The registers cache and index expected to be set before call.
+// The function may destroy various registers, just not the cache and index registers.
+void TemplateTable::jvmti_post_field_mod(Register Rcache, Register Rscratch, bool is_static) {
+
+ assert_different_registers(Rcache, Rscratch, R6_ARG4);
+
+ if (JvmtiExport::can_post_field_modification()) {
+ Label Lno_field_mod_post;
+
+ // Check if post field access in enabled.
+ int offs = __ load_const_optimized(Rscratch, JvmtiExport::get_field_modification_count_addr(), R0, true);
+ __ lwz(Rscratch, offs, Rscratch);
+
+ __ cmpwi(CCR0, Rscratch, 0);
+ __ beq(CCR0, Lno_field_mod_post);
+
+ // Do the post
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+ const Register Robj = Rscratch;
+
+ __ addi(Rcache, Rcache, in_bytes(cp_base_offset));
+ if (is_static) {
+ // Life is simple. Null out the object pointer.
+ __ li(Robj, 0);
+ } else {
+ // In case of the fast versions, value lives in registers => put it back on tos.
+ int offs = Interpreter::expr_offset_in_bytes(0);
+ Register base = R15_esp;
+ switch(bytecode()) {
+ case Bytecodes::_fast_aputfield: __ push_ptr(); offs+= Interpreter::stackElementSize; break;
+ case Bytecodes::_fast_iputfield: // Fall through
+ case Bytecodes::_fast_bputfield: // Fall through
+ case Bytecodes::_fast_cputfield: // Fall through
+ case Bytecodes::_fast_sputfield: __ push_i(); offs+= Interpreter::stackElementSize; break;
+ case Bytecodes::_fast_lputfield: __ push_l(); offs+=2*Interpreter::stackElementSize; break;
+ case Bytecodes::_fast_fputfield: __ push_f(); offs+= Interpreter::stackElementSize; break;
+ case Bytecodes::_fast_dputfield: __ push_d(); offs+=2*Interpreter::stackElementSize; break;
+ default: {
+ offs = 0;
+ base = Robj;
+ const Register Rflags = Robj;
+ Label is_one_slot;
+ // Life is harder. The stack holds the value on top, followed by the
+ // object. We don't know the size of the value, though; it could be
+ // one or two words depending on its type. As a result, we must find
+ // the type to determine where the object is.
+ __ ld(Rflags, in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcache); // Big Endian
+ __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+
+ __ cmpwi(CCR0, Rflags, ltos);
+ __ cmpwi(CCR1, Rflags, dtos);
+ __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(1));
+ __ crnor(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2);
+ __ beq(CCR0, is_one_slot);
+ __ addi(base, R15_esp, Interpreter::expr_offset_in_bytes(2));
+ __ bind(is_one_slot);
+ break;
+ }
+ }
+ __ ld(Robj, offs, base);
+ __ verify_oop(Robj);
+ }
+
+ __ addi(R6_ARG4, R15_esp, Interpreter::expr_offset_in_bytes(0));
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), Robj, Rcache, R6_ARG4);
+ __ get_cache_and_index_at_bcp(Rcache, 1);
+
+ // In case of the fast versions, value lives in registers => put it back on tos.
+ switch(bytecode()) {
+ case Bytecodes::_fast_aputfield: __ pop_ptr(); break;
+ case Bytecodes::_fast_iputfield: // Fall through
+ case Bytecodes::_fast_bputfield: // Fall through
+ case Bytecodes::_fast_cputfield: // Fall through
+ case Bytecodes::_fast_sputfield: __ pop_i(); break;
+ case Bytecodes::_fast_lputfield: __ pop_l(); break;
+ case Bytecodes::_fast_fputfield: __ pop_f(); break;
+ case Bytecodes::_fast_dputfield: __ pop_d(); break;
+ default: break; // Nothin' to do.
+ }
+
+ __ align(32, 12);
+ __ bind(Lno_field_mod_post);
+ }
+}
+
+// PPC64: implement volatile stores as release-store (return bytecode contains an additional release).
+void TemplateTable::putfield_or_static(int byte_no, bool is_static) {
+ Label Lvolatile;
+
+ const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod).
+ Rclass_or_obj = R31, // Needs to survive C call.
+ Roffset = R22_tmp2, // Needs to survive C call.
+ Rflags = R3_ARG1,
+ Rbtable = R4_ARG2,
+ Rscratch = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rscratch3 = R6_ARG4,
+ Rbc = Rscratch3;
+ const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store).
+
+ static address field_branch_table[number_of_states],
+ static_branch_table[number_of_states];
+
+ address* branch_table = is_static ? static_branch_table : field_branch_table;
+
+ // Stack (grows up):
+ // value
+ // obj
+
+ // Load the field offset.
+ resolve_cache_and_index(byte_no, Rcache, Rscratch, sizeof(u2));
+ jvmti_post_field_mod(Rcache, Rscratch, is_static);
+ load_field_cp_cache_entry(Rclass_or_obj, Rcache, noreg, Roffset, Rflags, is_static);
+
+ // Load pointer to branch table.
+ __ load_const_optimized(Rbtable, (address)branch_table, Rscratch);
+
+ // Get volatile flag.
+ __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit.
+
+ // Check the field type.
+ __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+
+#ifdef ASSERT
+ Label LFlagInvalid;
+ __ cmpldi(CCR0, Rflags, number_of_states);
+ __ bge(CCR0, LFlagInvalid);
+#endif
+
+ // Load from branch table and dispatch (volatile case: one instruction ahead).
+ __ sldi(Rflags, Rflags, LogBytesPerWord);
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpwi(CR_is_vol, Rscratch, 1); } // Volatile?
+ __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // Volatile? size of instruction 1 : 0.
+ __ ldx(Rbtable, Rbtable, Rflags);
+
+ __ subf(Rbtable, Rscratch, Rbtable); // Point to volatile/non-volatile entry point.
+ __ mtctr(Rbtable);
+ __ bctr();
+
+#ifdef ASSERT
+ __ bind(LFlagInvalid);
+ __ stop("got invalid flag", 0x656);
+
+ // __ bind(Lvtos);
+ address pc_before_release = __ pc();
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(__ pc() - pc_before_release == (ptrdiff_t)BytesPerInstWord, "must be single instruction");
+ assert(branch_table[vtos] == 0, "can't compute twice");
+ branch_table[vtos] = __ pc(); // non-volatile_entry point
+ __ stop("vtos unexpected", 0x657);
+#endif
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Ldtos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[dtos] == 0, "can't compute twice");
+ branch_table[dtos] = __ pc(); // non-volatile_entry point
+ __ pop(dtos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ stfdx(F15_ftos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_dputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Lftos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ftos] == 0, "can't compute twice");
+ branch_table[ftos] = __ pc(); // non-volatile_entry point
+ __ pop(ftos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ stfsx(F15_ftos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_fputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Litos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[itos] == 0, "can't compute twice");
+ branch_table[itos] = __ pc(); // non-volatile_entry point
+ __ pop(itos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ stwx(R17_tos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_iputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Lltos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ltos] == 0, "can't compute twice");
+ branch_table[ltos] = __ pc(); // non-volatile_entry point
+ __ pop(ltos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ stdx(R17_tos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_lputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Lbtos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[btos] == 0, "can't compute twice");
+ branch_table[btos] = __ pc(); // non-volatile_entry point
+ __ pop(btos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ stbx(R17_tos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_bputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Lctos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[ctos] == 0, "can't compute twice");
+ branch_table[ctos] = __ pc(); // non-volatile_entry point
+ __ pop(ctos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1..
+ __ sthx(R17_tos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_cputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Lstos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[stos] == 0, "can't compute twice");
+ branch_table[stos] = __ pc(); // non-volatile_entry point
+ __ pop(stos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // Kills R11_scratch1.
+ __ sthx(R17_tos, Rclass_or_obj, Roffset);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_sputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ }
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 28, 28); // Align pop.
+ // __ bind(Latos);
+ __ release(); // Volatile entry point (one instruction before non-volatile_entry point).
+ assert(branch_table[atos] == 0, "can't compute twice");
+ branch_table[atos] = __ pc(); // non-volatile_entry point
+ __ pop(atos);
+ if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1
+ do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */);
+ if (!is_static) { patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no); }
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ __ beq(CR_is_vol, Lvolatile); // Volatile?
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 12);
+ __ bind(Lvolatile);
+ __ fence();
+ }
+ // fallthru: __ b(Lexit);
+
+#ifdef ASSERT
+ for (int i = 0; iprint_cr("put: %s_branch_table[%d] = 0x%llx (opcode 0x%llx)",
+ // is_static ? "static" : "field", i, branch_table[i], *((unsigned int*)branch_table[i]));
+ }
+#endif
+}
+
+void TemplateTable::putfield(int byte_no) {
+ putfield_or_static(byte_no, false);
+}
+
+void TemplateTable::putstatic(int byte_no) {
+ putfield_or_static(byte_no, true);
+}
+
+// See SPARC. On PPC64, we have a different jvmti_post_field_mod which does the job.
+void TemplateTable::jvmti_post_fast_field_mod() {
+ __ should_not_reach_here();
+}
+
+void TemplateTable::fast_storefield(TosState state) {
+ transition(state, vtos);
+
+ const Register Rcache = R5_ARG3, // Do not use ARG1/2 (causes trouble in jvmti_post_field_mod).
+ Rclass_or_obj = R31, // Needs to survive C call.
+ Roffset = R22_tmp2, // Needs to survive C call.
+ Rflags = R3_ARG1,
+ Rscratch = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rscratch3 = R4_ARG2;
+ const ConditionRegister CR_is_vol = CCR2; // Non-volatile condition register (survives runtime call in do_oop_store).
+
+ // Constant pool already resolved => Load flags and offset of field.
+ __ get_cache_and_index_at_bcp(Rcache, 1);
+ jvmti_post_field_mod(Rcache, Rscratch, false /* not static */);
+ load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false);
+
+ // Get the obj and the final store addr.
+ pop_and_check_object(Rclass_or_obj); // Kills R11_scratch1.
+
+ // Get volatile flag.
+ __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit.
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { __ cmpdi(CR_is_vol, Rscratch, 1); }
+ {
+ Label LnotVolatile;
+ __ beq(CCR0, LnotVolatile);
+ __ release();
+ __ align(32, 12);
+ __ bind(LnotVolatile);
+ }
+
+ // Do the store and fencing.
+ switch(bytecode()) {
+ case Bytecodes::_fast_aputfield:
+ // Store into the field.
+ do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */);
+ break;
+
+ case Bytecodes::_fast_iputfield:
+ __ stwx(R17_tos, Rclass_or_obj, Roffset);
+ break;
+
+ case Bytecodes::_fast_lputfield:
+ __ stdx(R17_tos, Rclass_or_obj, Roffset);
+ break;
+
+ case Bytecodes::_fast_bputfield:
+ __ stbx(R17_tos, Rclass_or_obj, Roffset);
+ break;
+
+ case Bytecodes::_fast_cputfield:
+ case Bytecodes::_fast_sputfield:
+ __ sthx(R17_tos, Rclass_or_obj, Roffset);
+ break;
+
+ case Bytecodes::_fast_fputfield:
+ __ stfsx(F15_ftos, Rclass_or_obj, Roffset);
+ break;
+
+ case Bytecodes::_fast_dputfield:
+ __ stfdx(F15_ftos, Rclass_or_obj, Roffset);
+ break;
+
+ default: ShouldNotReachHere();
+ }
+
+ if (!support_IRIW_for_not_multiple_copy_atomic_cpu) {
+ Label LVolatile;
+ __ beq(CR_is_vol, LVolatile);
+ __ dispatch_epilog(vtos, Bytecodes::length_for(bytecode()));
+
+ __ align(32, 12);
+ __ bind(LVolatile);
+ __ fence();
+ }
+}
+
+void TemplateTable::fast_accessfield(TosState state) {
+ transition(atos, state);
+
+ Label LisVolatile;
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+
+ const Register Rcache = R3_ARG1,
+ Rclass_or_obj = R17_tos,
+ Roffset = R22_tmp2,
+ Rflags = R23_tmp3,
+ Rscratch = R12_scratch2;
+
+ // Constant pool already resolved. Get the field offset.
+ __ get_cache_and_index_at_bcp(Rcache, 1);
+ load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false);
+
+ // JVMTI support
+ jvmti_post_field_access(Rcache, Rscratch, false, true);
+
+ // Get the load address.
+ __ null_check_throw(Rclass_or_obj, -1, Rscratch);
+
+ // Get volatile flag.
+ __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit.
+ __ bne(CCR0, LisVolatile);
+
+ switch(bytecode()) {
+ case Bytecodes::_fast_agetfield:
+ {
+ __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ __ verify_oop(R17_tos);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ __ verify_oop(R17_tos);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_igetfield:
+ {
+ __ lwax(R17_tos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lwax(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_lgetfield:
+ {
+ __ ldx(R17_tos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ ldx(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_bgetfield:
+ {
+ __ lbzx(R17_tos, Rclass_or_obj, Roffset);
+ __ extsb(R17_tos, R17_tos);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lbzx(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ extsb(R17_tos, R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_cgetfield:
+ {
+ __ lhzx(R17_tos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lhzx(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_sgetfield:
+ {
+ __ lhax(R17_tos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lhax(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_fgetfield:
+ {
+ __ lfsx(F15_ftos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ Label Ldummy;
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lfsx(F15_ftos, Rclass_or_obj, Roffset);
+ __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync.
+ __ bne_predict_not_taken(CCR0, Ldummy);
+ __ bind(Ldummy);
+ __ isync();
+ break;
+ }
+ case Bytecodes::_fast_dgetfield:
+ {
+ __ lfdx(F15_ftos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
+
+ __ bind(LisVolatile);
+ Label Ldummy;
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lfdx(F15_ftos, Rclass_or_obj, Roffset);
+ __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync.
+ __ bne_predict_not_taken(CCR0, Ldummy);
+ __ bind(Ldummy);
+ __ isync();
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+}
+
+void TemplateTable::fast_xaccess(TosState state) {
+ transition(vtos, state);
+
+ Label LisVolatile;
+ ByteSize cp_base_offset = ConstantPoolCache::base_offset();
+ const Register Rcache = R3_ARG1,
+ Rclass_or_obj = R17_tos,
+ Roffset = R22_tmp2,
+ Rflags = R23_tmp3,
+ Rscratch = R12_scratch2;
+
+ __ ld(Rclass_or_obj, 0, R18_locals);
+
+ // Constant pool already resolved. Get the field offset.
+ __ get_cache_and_index_at_bcp(Rcache, 2);
+ load_field_cp_cache_entry(noreg, Rcache, noreg, Roffset, Rflags, false);
+
+ // JVMTI support not needed, since we switch back to single bytecode as soon as debugger attaches.
+
+ // Needed to report exception at the correct bcp.
+ __ addi(R14_bcp, R14_bcp, 1);
+
+ // Get the load address.
+ __ null_check_throw(Rclass_or_obj, -1, Rscratch);
+
+ // Get volatile flag.
+ __ rldicl_(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // Extract volatile bit.
+ __ bne(CCR0, LisVolatile);
+
+ switch(state) {
+ case atos:
+ {
+ __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ __ verify_oop(R17_tos);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment.
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ __ verify_oop(R17_tos);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case itos:
+ {
+ __ lwax(R17_tos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment.
+
+ __ bind(LisVolatile);
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lwax(R17_tos, Rclass_or_obj, Roffset);
+ __ twi_0(R17_tos);
+ __ isync();
+ break;
+ }
+ case ftos:
+ {
+ __ lfsx(F15_ftos, Rclass_or_obj, Roffset);
+ __ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment.
+
+ __ bind(LisVolatile);
+ Label Ldummy;
+ if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
+ __ lfsx(F15_ftos, Rclass_or_obj, Roffset);
+ __ fcmpu(CCR0, F15_ftos, F15_ftos); // Acquire by cmp-br-isync.
+ __ bne_predict_not_taken(CCR0, Ldummy);
+ __ bind(Ldummy);
+ __ isync();
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+ __ addi(R14_bcp, R14_bcp, -1);
+}
+
+// ============================================================================
+// Calls
+
+// Common code for invoke
+//
+// Input:
+// - byte_no
+//
+// Output:
+// - Rmethod: The method to invoke next.
+// - Rret_addr: The return address to return to.
+// - Rindex: MethodType (invokehandle) or CallSite obj (invokedynamic)
+// - Rrecv: Cache for "this" pointer, might be noreg if static call.
+// - Rflags: Method flags from const pool cache.
+//
+// Kills:
+// - Rscratch1
+//
+void TemplateTable::prepare_invoke(int byte_no,
+ Register Rmethod, // linked method (or i-klass)
+ Register Rret_addr,// return address
+ Register Rindex, // itable index, MethodType, etc.
+ Register Rrecv, // If caller wants to see it.
+ Register Rflags, // If caller wants to test it.
+ Register Rscratch
+ ) {
+ // Determine flags.
+ const Bytecodes::Code code = bytecode();
+ const bool is_invokeinterface = code == Bytecodes::_invokeinterface;
+ const bool is_invokedynamic = code == Bytecodes::_invokedynamic;
+ const bool is_invokehandle = code == Bytecodes::_invokehandle;
+ const bool is_invokevirtual = code == Bytecodes::_invokevirtual;
+ const bool is_invokespecial = code == Bytecodes::_invokespecial;
+ const bool load_receiver = (Rrecv != noreg);
+ assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), "");
+
+ assert_different_registers(Rmethod, Rindex, Rflags, Rscratch);
+ assert_different_registers(Rmethod, Rrecv, Rflags, Rscratch);
+ assert_different_registers(Rret_addr, Rscratch);
+
+ load_invoke_cp_cache_entry(byte_no, Rmethod, Rindex, Rflags, is_invokevirtual, false, is_invokedynamic);
+
+ // Saving of SP done in call_from_interpreter.
+
+ // Maybe push "appendix" to arguments.
+ if (is_invokedynamic || is_invokehandle) {
+ Label Ldone;
+ __ rldicl_(R0, Rflags, 64-ConstantPoolCacheEntry::has_appendix_shift, 63);
+ __ beq(CCR0, Ldone);
+ // Push "appendix" (MethodType, CallSite, etc.).
+ // This must be done before we get the receiver,
+ // since the parameter_size includes it.
+ __ load_resolved_reference_at_index(Rscratch, Rindex);
+ __ verify_oop(Rscratch);
+ __ push_ptr(Rscratch);
+ __ bind(Ldone);
+ }
+
+ // Load receiver if needed (after appendix is pushed so parameter size is correct).
+ if (load_receiver) {
+ const Register Rparam_count = Rscratch;
+ __ andi(Rparam_count, Rflags, ConstantPoolCacheEntry::parameter_size_mask);
+ __ load_receiver(Rparam_count, Rrecv);
+ __ verify_oop(Rrecv);
+ }
+
+ // Get return address.
+ {
+ Register Rtable_addr = Rscratch;
+ Register Rret_type = Rret_addr;
+ address table_addr = (address) Interpreter::invoke_return_entry_table_for(code);
+
+ // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value.
+ __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+ __ load_dispatch_table(Rtable_addr, (address*)table_addr);
+ __ sldi(Rret_type, Rret_type, LogBytesPerWord);
+ // Get return address.
+ __ ldx(Rret_addr, Rtable_addr, Rret_type);
+ }
+}
+
+// Helper for virtual calls. Load target out of vtable and jump off!
+// Kills all passed registers.
+void TemplateTable::generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp) {
+
+ assert_different_registers(Rrecv_klass, Rtemp, Rret);
+ const Register Rtarget_method = Rindex;
+
+ // Get target method & entry point.
+ const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ // Calc vtable addr scale the vtable index by 8.
+ __ sldi(Rindex, Rindex, exact_log2(vtableEntry::size() * wordSize));
+ // Load target.
+ __ addi(Rrecv_klass, Rrecv_klass, base + vtableEntry::method_offset_in_bytes());
+ __ ldx(Rtarget_method, Rindex, Rrecv_klass);
+ __ call_from_interpreter(Rtarget_method, Rret, Rrecv_klass /* scratch1 */, Rtemp /* scratch2 */);
+}
+
+// Virtual or final call. Final calls are rewritten on the fly to run through "fast_finalcall" next time.
+void TemplateTable::invokevirtual(int byte_no) {
+ transition(vtos, vtos);
+
+ Register Rtable_addr = R11_scratch1,
+ Rret_type = R12_scratch2,
+ Rret_addr = R5_ARG3,
+ Rflags = R22_tmp2, // Should survive C call.
+ Rrecv = R3_ARG1,
+ Rrecv_klass = Rrecv,
+ Rvtableindex_or_method = R31, // Should survive C call.
+ Rnum_params = R4_ARG2,
+ Rnew_bc = R6_ARG4;
+
+ Label LnotFinal;
+
+ load_invoke_cp_cache_entry(byte_no, Rvtableindex_or_method, noreg, Rflags, /*virtual*/ true, false, false);
+
+ __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift);
+ __ bfalse(CCR0, LnotFinal);
+
+ patch_bytecode(Bytecodes::_fast_invokevfinal, Rnew_bc, R12_scratch2);
+ invokevfinal_helper(Rvtableindex_or_method, Rflags, R11_scratch1, R12_scratch2);
+
+ __ align(32, 12);
+ __ bind(LnotFinal);
+ // Load "this" pointer (receiver).
+ __ rldicl(Rnum_params, Rflags, 64, 48);
+ __ load_receiver(Rnum_params, Rrecv);
+ __ verify_oop(Rrecv);
+
+ // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value.
+ __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+ __ load_dispatch_table(Rtable_addr, Interpreter::invoke_return_entry_table());
+ __ sldi(Rret_type, Rret_type, LogBytesPerWord);
+ __ ldx(Rret_addr, Rret_type, Rtable_addr);
+ __ null_check_throw(Rrecv, oopDesc::klass_offset_in_bytes(), R11_scratch1);
+ __ load_klass(Rrecv_klass, Rrecv);
+ __ verify_klass_ptr(Rrecv_klass);
+ __ profile_virtual_call(Rrecv_klass, R11_scratch1, R12_scratch2, false);
+
+ generate_vtable_call(Rrecv_klass, Rvtableindex_or_method, Rret_addr, R11_scratch1);
+}
+
+void TemplateTable::fast_invokevfinal(int byte_no) {
+ transition(vtos, vtos);
+
+ assert(byte_no == f2_byte, "use this argument");
+ Register Rflags = R22_tmp2,
+ Rmethod = R31;
+ load_invoke_cp_cache_entry(byte_no, Rmethod, noreg, Rflags, /*virtual*/ true, /*is_invokevfinal*/ true, false);
+ invokevfinal_helper(Rmethod, Rflags, R11_scratch1, R12_scratch2);
+}
+
+void TemplateTable::invokevfinal_helper(Register Rmethod, Register Rflags, Register Rscratch1, Register Rscratch2) {
+
+ assert_different_registers(Rmethod, Rflags, Rscratch1, Rscratch2);
+
+ // Load receiver from stack slot.
+ Register Rrecv = Rscratch2;
+ Register Rnum_params = Rrecv;
+
+ __ ld(Rnum_params, in_bytes(Method::const_offset()), Rmethod);
+ __ lhz(Rnum_params /* number of params */, in_bytes(ConstMethod::size_of_parameters_offset()), Rnum_params);
+
+ // Get return address.
+ Register Rtable_addr = Rscratch1,
+ Rret_addr = Rflags,
+ Rret_type = Rret_addr;
+ // Get return type. It's coded into the upper 4 bits of the lower half of the 64 bit value.
+ __ rldicl(Rret_type, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits);
+ __ load_dispatch_table(Rtable_addr, Interpreter::invoke_return_entry_table());
+ __ sldi(Rret_type, Rret_type, LogBytesPerWord);
+ __ ldx(Rret_addr, Rret_type, Rtable_addr);
+
+ // Load receiver and receiver NULL check.
+ __ load_receiver(Rnum_params, Rrecv);
+ __ null_check_throw(Rrecv, -1, Rscratch1);
+
+ __ profile_final_call(Rrecv, Rscratch1);
+
+ // Do the call.
+ __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1, Rscratch2);
+}
+
+void TemplateTable::invokespecial(int byte_no) {
+ assert(byte_no == f1_byte, "use this argument");
+ transition(vtos, vtos);
+
+ Register Rtable_addr = R3_ARG1,
+ Rret_addr = R4_ARG2,
+ Rflags = R5_ARG3,
+ Rreceiver = R6_ARG4,
+ Rmethod = R31;
+
+ prepare_invoke(byte_no, Rmethod, Rret_addr, noreg, Rreceiver, Rflags, R11_scratch1);
+
+ // Receiver NULL check.
+ __ null_check_throw(Rreceiver, -1, R11_scratch1);
+
+ __ profile_call(R11_scratch1, R12_scratch2);
+ __ call_from_interpreter(Rmethod, Rret_addr, R11_scratch1, R12_scratch2);
+}
+
+void TemplateTable::invokestatic(int byte_no) {
+ assert(byte_no == f1_byte, "use this argument");
+ transition(vtos, vtos);
+
+ Register Rtable_addr = R3_ARG1,
+ Rret_addr = R4_ARG2,
+ Rflags = R5_ARG3;
+
+ prepare_invoke(byte_no, R19_method, Rret_addr, noreg, noreg, Rflags, R11_scratch1);
+
+ __ profile_call(R11_scratch1, R12_scratch2);
+ __ call_from_interpreter(R19_method, Rret_addr, R11_scratch1, R12_scratch2);
+}
+
+void TemplateTable::invokeinterface_object_method(Register Rrecv_klass,
+ Register Rret,
+ Register Rflags,
+ Register Rindex,
+ Register Rtemp1,
+ Register Rtemp2) {
+
+ assert_different_registers(Rindex, Rret, Rrecv_klass, Rflags, Rtemp1, Rtemp2);
+ Label LnotFinal;
+
+ // Check for vfinal.
+ __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_vfinal_shift);
+ __ bfalse(CCR0, LnotFinal);
+
+ Register Rscratch = Rflags; // Rflags is dead now.
+
+ // Final call case.
+ __ profile_final_call(Rtemp1, Rscratch);
+ // Do the final call - the index (f2) contains the method.
+ __ call_from_interpreter(Rindex, Rret, Rscratch, Rrecv_klass /* scratch */);
+
+ // Non-final callc case.
+ __ bind(LnotFinal);
+ __ profile_virtual_call(Rrecv_klass, Rtemp1, Rscratch, false);
+ generate_vtable_call(Rrecv_klass, Rindex, Rret, Rscratch);
+}
+
+void TemplateTable::invokeinterface(int byte_no) {
+ assert(byte_no == f1_byte, "use this argument");
+ transition(vtos, vtos);
+
+ const Register Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2,
+ Rscratch3 = R9_ARG7,
+ Rscratch4 = R10_ARG8,
+ Rtable_addr = Rscratch2,
+ Rinterface_klass = R5_ARG3,
+ Rret_type = R8_ARG6,
+ Rret_addr = Rret_type,
+ Rindex = R6_ARG4,
+ Rreceiver = R4_ARG2,
+ Rrecv_klass = Rreceiver,
+ Rflags = R7_ARG5;
+
+ prepare_invoke(byte_no, Rinterface_klass, Rret_addr, Rindex, Rreceiver, Rflags, Rscratch1);
+
+ // Get receiver klass.
+ __ null_check_throw(Rreceiver, oopDesc::klass_offset_in_bytes(), Rscratch3);
+ __ load_klass(Rrecv_klass, Rreceiver);
+
+ // Check corner case object method.
+ Label LobjectMethod;
+
+ __ testbitdi(CCR0, R0, Rflags, ConstantPoolCacheEntry::is_forced_virtual_shift);
+ __ btrue(CCR0, LobjectMethod);
+
+ // Fallthrough: The normal invokeinterface case.
+ __ profile_virtual_call(Rrecv_klass, Rscratch1, Rscratch2, false);
+
+ // Find entry point to call.
+ Label Lthrow_icc, Lthrow_ame;
+ // Result will be returned in Rindex.
+ __ mr(Rscratch4, Rrecv_klass);
+ __ mr(Rscratch3, Rindex);
+ __ lookup_interface_method(Rrecv_klass, Rinterface_klass, Rindex, Rindex, Rscratch1, Rscratch2, Lthrow_icc);
+
+ __ cmpdi(CCR0, Rindex, 0);
+ __ beq(CCR0, Lthrow_ame);
+ // Found entry. Jump off!
+ __ call_from_interpreter(Rindex, Rret_addr, Rscratch1, Rscratch2);
+
+ // Vtable entry was NULL => Throw abstract method error.
+ __ bind(Lthrow_ame);
+ __ mr(Rrecv_klass, Rscratch4);
+ __ mr(Rindex, Rscratch3);
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
+
+ // Interface was not found => Throw incompatible class change error.
+ __ bind(Lthrow_icc);
+ __ mr(Rrecv_klass, Rscratch4);
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
+
+ __ should_not_reach_here();
+
+ // Special case of invokeinterface called for virtual method of
+ // java.lang.Object. See ConstantPoolCacheEntry::set_method() for details:
+ // The invokeinterface was rewritten to a invokevirtual, hence we have
+ // to handle this corner case. This code isn't produced by javac, but could
+ // be produced by another compliant java compiler.
+ __ bind(LobjectMethod);
+ invokeinterface_object_method(Rrecv_klass, Rret_addr, Rflags, Rindex, Rscratch1, Rscratch2);
+}
+
+void TemplateTable::invokedynamic(int byte_no) {
+ transition(vtos, vtos);
+
+ const Register Rret_addr = R3_ARG1,
+ Rflags = R4_ARG2,
+ Rmethod = R22_tmp2,
+ Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2;
+
+ if (!EnableInvokeDynamic) {
+ // We should not encounter this bytecode if !EnableInvokeDynamic.
+ // The verifier will stop it. However, if we get past the verifier,
+ // this will stop the thread in a reasonable way, without crashing the JVM.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeError));
+ // The call_VM checks for exception, so we should never return here.
+ __ should_not_reach_here();
+ return;
+ }
+
+ prepare_invoke(byte_no, Rmethod, Rret_addr, Rscratch1, noreg, Rflags, Rscratch2);
+
+ // Profile this call.
+ __ profile_call(Rscratch1, Rscratch2);
+
+ // Off we go. With the new method handles, we don't jump to a method handle
+ // entry any more. Instead, we pushed an "appendix" in prepare invoke, which happens
+ // to be the callsite object the bootstrap method returned. This is passed to a
+ // "link" method which does the dispatch (Most likely just grabs the MH stored
+ // inside the callsite and does an invokehandle).
+ __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */);
+}
+
+void TemplateTable::invokehandle(int byte_no) {
+ transition(vtos, vtos);
+
+ const Register Rret_addr = R3_ARG1,
+ Rflags = R4_ARG2,
+ Rrecv = R5_ARG3,
+ Rmethod = R22_tmp2,
+ Rscratch1 = R11_scratch1,
+ Rscratch2 = R12_scratch2;
+
+ if (!EnableInvokeDynamic) {
+ // Rewriter does not generate this bytecode.
+ __ should_not_reach_here();
+ return;
+ }
+
+ prepare_invoke(byte_no, Rmethod, Rret_addr, Rscratch1, Rrecv, Rflags, Rscratch2);
+ __ verify_method_ptr(Rmethod);
+ __ null_check_throw(Rrecv, -1, Rscratch2);
+
+ __ profile_final_call(Rrecv, Rscratch1);
+
+ // Still no call from handle => We call the method handle interpreter here.
+ __ call_from_interpreter(Rmethod, Rret_addr, Rscratch1 /* scratch1 */, Rscratch2 /* scratch2 */);
+}
+
+// =============================================================================
+// Allocation
+
+// Puts allocated obj ref onto the expression stack.
+void TemplateTable::_new() {
+ transition(vtos, atos);
+
+ Label Lslow_case,
+ Ldone,
+ Linitialize_header,
+ Lallocate_shared,
+ Linitialize_object; // Including clearing the fields.
+
+ const Register RallocatedObject = R17_tos,
+ RinstanceKlass = R9_ARG7,
+ Rscratch = R11_scratch1,
+ Roffset = R8_ARG6,
+ Rinstance_size = Roffset,
+ Rcpool = R4_ARG2,
+ Rtags = R3_ARG1,
+ Rindex = R5_ARG3;
+
+ const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
+
+ // --------------------------------------------------------------------------
+ // Check if fast case is possible.
+
+ // Load pointers to const pool and const pool's tags array.
+ __ get_cpool_and_tags(Rcpool, Rtags);
+ // Load index of constant pool entry.
+ __ get_2_byte_integer_at_bcp(1, Rindex, InterpreterMacroAssembler::Unsigned);
+
+ if (UseTLAB) {
+ // Make sure the class we're about to instantiate has been resolved
+ // This is done before loading instanceKlass to be consistent with the order
+ // how Constant Pool is updated (see ConstantPoolCache::klass_at_put).
+ __ addi(Rtags, Rtags, Array::base_offset_in_bytes());
+ __ lbzx(Rtags, Rindex, Rtags);
+
+ __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class);
+ __ bne(CCR0, Lslow_case);
+
+ // Get instanceKlass (load from Rcpool + sizeof(ConstantPool) + Rindex*BytesPerWord).
+ __ sldi(Roffset, Rindex, LogBytesPerWord);
+ __ addi(Rscratch, Rcpool, sizeof(ConstantPool));
+ __ isync(); // Order load of instance Klass wrt. tags.
+ __ ldx(RinstanceKlass, Roffset, Rscratch);
+
+ // Make sure klass is fully initialized and get instance_size.
+ __ lbz(Rscratch, in_bytes(InstanceKlass::init_state_offset()), RinstanceKlass);
+ __ lwz(Rinstance_size, in_bytes(Klass::layout_helper_offset()), RinstanceKlass);
+
+ __ cmpdi(CCR1, Rscratch, InstanceKlass::fully_initialized);
+ // Make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class.
+ __ andi_(R0, Rinstance_size, Klass::_lh_instance_slow_path_bit); // slow path bit equals 0?
+
+ __ crnand(/*CR0 eq*/2, /*CR1 eq*/4+2, /*CR0 eq*/2); // slow path bit set or not fully initialized?
+ __ beq(CCR0, Lslow_case);
+
+ // --------------------------------------------------------------------------
+ // Fast case:
+ // Allocate the instance.
+ // 1) Try to allocate in the TLAB.
+ // 2) If fail, and the TLAB is not full enough to discard, allocate in the shared Eden.
+ // 3) If the above fails (or is not applicable), go to a slow case (creates a new TLAB, etc.).
+
+ Register RoldTopValue = RallocatedObject; // Object will be allocated here if it fits.
+ Register RnewTopValue = R6_ARG4;
+ Register RendValue = R7_ARG5;
+
+ // Check if we can allocate in the TLAB.
+ __ ld(RoldTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread);
+ __ ld(RendValue, in_bytes(JavaThread::tlab_end_offset()), R16_thread);
+
+ __ add(RnewTopValue, Rinstance_size, RoldTopValue);
+
+ // If there is enough space, we do not CAS and do not clear.
+ __ cmpld(CCR0, RnewTopValue, RendValue);
+ __ bgt(CCR0, allow_shared_alloc ? Lallocate_shared : Lslow_case);
+
+ __ std(RnewTopValue, in_bytes(JavaThread::tlab_top_offset()), R16_thread);
+
+ if (ZeroTLAB) {
+ // The fields have already been cleared.
+ __ b(Linitialize_header);
+ } else {
+ // Initialize both the header and fields.
+ __ b(Linitialize_object);
+ }
+
+ // Fall through: TLAB was too small.
+ if (allow_shared_alloc) {
+ Register RtlabWasteLimitValue = R10_ARG8;
+ Register RfreeValue = RnewTopValue;
+
+ __ bind(Lallocate_shared);
+ // Check if tlab should be discarded (refill_waste_limit >= free).
+ __ ld(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread);
+ __ subf(RfreeValue, RoldTopValue, RendValue);
+ __ srdi(RfreeValue, RfreeValue, LogHeapWordSize); // in dwords
+ __ cmpld(CCR0, RtlabWasteLimitValue, RfreeValue);
+ __ bge(CCR0, Lslow_case);
+
+ // Increment waste limit to prevent getting stuck on this slow path.
+ __ addi(RtlabWasteLimitValue, RtlabWasteLimitValue, (int)ThreadLocalAllocBuffer::refill_waste_limit_increment());
+ __ std(RtlabWasteLimitValue, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), R16_thread);
+ }
+ // else: No allocation in the shared eden. // fallthru: __ b(Lslow_case);
+ }
+ // else: Always go the slow path.
+
+ // --------------------------------------------------------------------------
+ // slow case
+ __ bind(Lslow_case);
+ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), Rcpool, Rindex);
+
+ if (UseTLAB) {
+ __ b(Ldone);
+ // --------------------------------------------------------------------------
+ // Init1: Zero out newly allocated memory.
+
+ if (!ZeroTLAB || allow_shared_alloc) {
+ // Clear object fields.
+ __ bind(Linitialize_object);
+
+ // Initialize remaining object fields.
+ Register Rbase = Rtags;
+ __ addi(Rinstance_size, Rinstance_size, 7 - (int)sizeof(oopDesc));
+ __ addi(Rbase, RallocatedObject, sizeof(oopDesc));
+ __ srdi(Rinstance_size, Rinstance_size, 3);
+
+ // Clear out object skipping header. Takes also care of the zero length case.
+ __ clear_memory_doubleword(Rbase, Rinstance_size);
+ // fallthru: __ b(Linitialize_header);
+ }
+
+ // --------------------------------------------------------------------------
+ // Init2: Initialize the header: mark, klass
+ __ bind(Linitialize_header);
+
+ // Init mark.
+ if (UseBiasedLocking) {
+ __ ld(Rscratch, in_bytes(Klass::prototype_header_offset()), RinstanceKlass);
+ } else {
+ __ load_const_optimized(Rscratch, markOopDesc::prototype(), R0);
+ }
+ __ std(Rscratch, oopDesc::mark_offset_in_bytes(), RallocatedObject);
+
+ // Init klass.
+ __ store_klass_gap(RallocatedObject);
+ __ store_klass(RallocatedObject, RinstanceKlass, Rscratch); // klass (last for cms)
+
+ // Check and trigger dtrace event.
+ {
+ SkipIfEqualZero skip_if(_masm, Rscratch, &DTraceAllocProbes);
+ __ push(atos);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc));
+ __ pop(atos);
+ }
+ }
+
+ // continue
+ __ bind(Ldone);
+
+ // Must prevent reordering of stores for object initialization with stores that publish the new object.
+ __ membar(Assembler::StoreStore);
+}
+
+void TemplateTable::newarray() {
+ transition(itos, atos);
+
+ __ lbz(R4, 1, R14_bcp);
+ __ extsw(R5, R17_tos);
+ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), R4, R5 /* size */);
+
+ // Must prevent reordering of stores for object initialization with stores that publish the new object.
+ __ membar(Assembler::StoreStore);
+}
+
+void TemplateTable::anewarray() {
+ transition(itos, atos);
+
+ __ get_constant_pool(R4);
+ __ get_2_byte_integer_at_bcp(1, R5, InterpreterMacroAssembler::Unsigned);
+ __ extsw(R6, R17_tos); // size
+ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), R4 /* pool */, R5 /* index */, R6 /* size */);
+
+ // Must prevent reordering of stores for object initialization with stores that publish the new object.
+ __ membar(Assembler::StoreStore);
+}
+
+// Allocate a multi dimensional array
+void TemplateTable::multianewarray() {
+ transition(vtos, atos);
+
+ Register Rptr = R31; // Needs to survive C call.
+
+ // Put ndims * wordSize into frame temp slot
+ __ lbz(Rptr, 3, R14_bcp);
+ __ sldi(Rptr, Rptr, Interpreter::logStackElementSize);
+ // Esp points past last_dim, so set to R4 to first_dim address.
+ __ add(R4, Rptr, R15_esp);
+ call_VM(R17_tos, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), R4 /* first_size_address */);
+ // Pop all dimensions off the stack.
+ __ add(R15_esp, Rptr, R15_esp);
+
+ // Must prevent reordering of stores for object initialization with stores that publish the new object.
+ __ membar(Assembler::StoreStore);
+}
+
+void TemplateTable::arraylength() {
+ transition(atos, itos);
+
+ Label LnoException;
+ __ verify_oop(R17_tos);
+ __ null_check_throw(R17_tos, arrayOopDesc::length_offset_in_bytes(), R11_scratch1);
+ __ lwa(R17_tos, arrayOopDesc::length_offset_in_bytes(), R17_tos);
+}
+
+// ============================================================================
+// Typechecks
+
+void TemplateTable::checkcast() {
+ transition(atos, atos);
+
+ Label Ldone, Lis_null, Lquicked, Lresolved;
+ Register Roffset = R5_ARG3,
+ RobjKlass = R4_ARG2,
+ RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect this register.
+ Rcpool = R11_scratch1,
+ Rtags = R12_scratch2;
+
+ // Null does not pass.
+ __ cmpdi(CCR0, R17_tos, 0);
+ __ beq(CCR0, Lis_null);
+
+ // Get constant pool tag to find out if the bytecode has already been "quickened".
+ __ get_cpool_and_tags(Rcpool, Rtags);
+
+ __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned);
+
+ __ addi(Rtags, Rtags, Array::base_offset_in_bytes());
+ __ lbzx(Rtags, Rtags, Roffset);
+
+ __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class);
+ __ beq(CCR0, Lquicked);
+
+ // Call into the VM to "quicken" instanceof.
+ __ push_ptr(); // for GC
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
+ __ get_vm_result_2(RspecifiedKlass);
+ __ pop_ptr(); // Restore receiver.
+ __ b(Lresolved);
+
+ // Extract target class from constant pool.
+ __ bind(Lquicked);
+ __ sldi(Roffset, Roffset, LogBytesPerWord);
+ __ addi(Rcpool, Rcpool, sizeof(ConstantPool));
+ __ isync(); // Order load of specified Klass wrt. tags.
+ __ ldx(RspecifiedKlass, Rcpool, Roffset);
+
+ // Do the checkcast.
+ __ bind(Lresolved);
+ // Get value klass in RobjKlass.
+ __ load_klass(RobjKlass, R17_tos);
+ // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure.
+ __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone);
+
+ // Not a subtype; so must throw exception
+ // Target class oop is in register R6_ARG4 == RspecifiedKlass by convention.
+ __ load_dispatch_table(R11_scratch1, (address*)Interpreter::_throw_ClassCastException_entry);
+ __ mtctr(R11_scratch1);
+ __ bctr();
+
+ // Profile the null case.
+ __ align(32, 12);
+ __ bind(Lis_null);
+ __ profile_null_seen(R11_scratch1, Rtags); // Rtags used as scratch.
+
+ __ align(32, 12);
+ __ bind(Ldone);
+}
+
+// Output:
+// - tos == 0: Obj was null or not an instance of class.
+// - tos == 1: Obj was an instance of class.
+void TemplateTable::instanceof() {
+ transition(atos, itos);
+
+ Label Ldone, Lis_null, Lquicked, Lresolved;
+ Register Roffset = R5_ARG3,
+ RobjKlass = R4_ARG2,
+ RspecifiedKlass = R6_ARG4, // Generate_ClassCastException_verbose_handler will expect the value in this register.
+ Rcpool = R11_scratch1,
+ Rtags = R12_scratch2;
+
+ // Null does not pass.
+ __ cmpdi(CCR0, R17_tos, 0);
+ __ beq(CCR0, Lis_null);
+
+ // Get constant pool tag to find out if the bytecode has already been "quickened".
+ __ get_cpool_and_tags(Rcpool, Rtags);
+
+ __ get_2_byte_integer_at_bcp(1, Roffset, InterpreterMacroAssembler::Unsigned);
+
+ __ addi(Rtags, Rtags, Array::base_offset_in_bytes());
+ __ lbzx(Rtags, Rtags, Roffset);
+
+ __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class);
+ __ beq(CCR0, Lquicked);
+
+ // Call into the VM to "quicken" instanceof.
+ __ push_ptr(); // for GC
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc));
+ __ get_vm_result_2(RspecifiedKlass);
+ __ pop_ptr(); // Restore receiver.
+ __ b(Lresolved);
+
+ // Extract target class from constant pool.
+ __ bind(Lquicked);
+ __ sldi(Roffset, Roffset, LogBytesPerWord);
+ __ addi(Rcpool, Rcpool, sizeof(ConstantPool));
+ __ isync(); // Order load of specified Klass wrt. tags.
+ __ ldx(RspecifiedKlass, Rcpool, Roffset);
+
+ // Do the checkcast.
+ __ bind(Lresolved);
+ // Get value klass in RobjKlass.
+ __ load_klass(RobjKlass, R17_tos);
+ // Generate a fast subtype check. Branch to cast_ok if no failure. Return 0 if failure.
+ __ li(R17_tos, 1);
+ __ gen_subtype_check(RobjKlass, RspecifiedKlass, /*3 temp regs*/ Roffset, Rcpool, Rtags, /*target if subtype*/ Ldone);
+ __ li(R17_tos, 0);
+
+ if (ProfileInterpreter) {
+ __ b(Ldone);
+ }
+
+ // Profile the null case.
+ __ align(32, 12);
+ __ bind(Lis_null);
+ __ profile_null_seen(Rcpool, Rtags); // Rcpool and Rtags used as scratch.
+
+ __ align(32, 12);
+ __ bind(Ldone);
+}
+
+// =============================================================================
+// Breakpoints
+
+void TemplateTable::_breakpoint() {
+ transition(vtos, vtos);
+
+ // Get the unpatched byte code.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), R19_method, R14_bcp);
+ __ mr(R31, R3_RET);
+
+ // Post the breakpoint event.
+ __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), R19_method, R14_bcp);
+
+ // Complete the execution of original bytecode.
+ __ dispatch_Lbyte_code(vtos, R31, Interpreter::normal_table(vtos));
+}
+
+// =============================================================================
+// Exceptions
+
+void TemplateTable::athrow() {
+ transition(atos, vtos);
+
+ // Exception oop is in tos
+ __ verify_oop(R17_tos);
+
+ __ null_check_throw(R17_tos, -1, R11_scratch1);
+
+ // Throw exception interpreter entry expects exception oop to be in R3.
+ __ mr(R3_RET, R17_tos);
+ __ load_dispatch_table(R11_scratch1, (address*)Interpreter::throw_exception_entry());
+ __ mtctr(R11_scratch1);
+ __ bctr();
+}
+
+// =============================================================================
+// Synchronization
+// Searches the basic object lock list on the stack for a free slot
+// and uses it to lock the obect in tos.
+//
+// Recursive locking is enabled by exiting the search if the same
+// object is already found in the list. Thus, a new basic lock obj lock
+// is allocated "higher up" in the stack and thus is found first
+// at next monitor exit.
+void TemplateTable::monitorenter() {
+ transition(atos, vtos);
+
+ __ verify_oop(R17_tos);
+
+ Register Rcurrent_monitor = R11_scratch1,
+ Rcurrent_obj = R12_scratch2,
+ Robj_to_lock = R17_tos,
+ Rscratch1 = R3_ARG1,
+ Rscratch2 = R4_ARG2,
+ Rscratch3 = R5_ARG3,
+ Rcurrent_obj_addr = R6_ARG4;
+
+ // ------------------------------------------------------------------------------
+ // Null pointer exception.
+ __ null_check_throw(Robj_to_lock, -1, R11_scratch1);
+
+ // Try to acquire a lock on the object.
+ // Repeat until succeeded (i.e., until monitorenter returns true).
+
+ // ------------------------------------------------------------------------------
+ // Find a free slot in the monitor block.
+ Label Lfound, Lexit, Lallocate_new;
+ ConditionRegister found_free_slot = CCR0,
+ found_same_obj = CCR1,
+ reached_limit = CCR6;
+ {
+ Label Lloop, Lentry;
+ Register Rlimit = Rcurrent_monitor;
+
+ // Set up search loop - start with topmost monitor.
+ __ add(Rcurrent_obj_addr, BasicObjectLock::obj_offset_in_bytes(), R26_monitor);
+
+ __ ld(Rlimit, 0, R1_SP);
+ __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes() - BasicObjectLock::obj_offset_in_bytes())); // Monitor base
+
+ // Check if any slot is present => short cut to allocation if not.
+ __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit);
+ __ bgt(reached_limit, Lallocate_new);
+
+ // Pre-load topmost slot.
+ __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize);
+ // The search loop.
+ __ bind(Lloop);
+ // Found free slot?
+ __ cmpdi(found_free_slot, Rcurrent_obj, 0);
+ // Is this entry for same obj? If so, stop the search and take the found
+ // free slot or allocate a new one to enable recursive locking.
+ __ cmpd(found_same_obj, Rcurrent_obj, Robj_to_lock);
+ __ cmpld(reached_limit, Rcurrent_obj_addr, Rlimit);
+ __ beq(found_free_slot, Lexit);
+ __ beq(found_same_obj, Lallocate_new);
+ __ bgt(reached_limit, Lallocate_new);
+ // Check if last allocated BasicLockObj reached.
+ __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize);
+ // Next iteration if unchecked BasicObjectLocks exist on the stack.
+ __ b(Lloop);
+ }
+
+ // ------------------------------------------------------------------------------
+ // Check if we found a free slot.
+ __ bind(Lexit);
+
+ __ addi(Rcurrent_monitor, Rcurrent_obj_addr, -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes());
+ __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, - frame::interpreter_frame_monitor_size() * wordSize);
+ __ b(Lfound);
+
+ // We didn't find a free BasicObjLock => allocate one.
+ __ align(32, 12);
+ __ bind(Lallocate_new);
+ __ add_monitor_to_stack(false, Rscratch1, Rscratch2);
+ __ mr(Rcurrent_monitor, R26_monitor);
+ __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes());
+
+ // ------------------------------------------------------------------------------
+ // We now have a slot to lock.
+ __ bind(Lfound);
+
+ // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly.
+ // The object has already been poped from the stack, so the expression stack looks correct.
+ __ addi(R14_bcp, R14_bcp, 1);
+
+ __ std(Robj_to_lock, 0, Rcurrent_obj_addr);
+ __ lock_object(Rcurrent_monitor, Robj_to_lock);
+
+ // Check if there's enough space on the stack for the monitors after locking.
+ Label Lskip_stack_check;
+ // Optimization: If the monitors stack section is less then a std page size (4K) don't run
+ // the stack check. There should be enough shadow pages to fit that in.
+ __ ld(Rscratch3, 0, R1_SP);
+ __ sub(Rscratch3, Rscratch3, R26_monitor);
+ __ cmpdi(CCR0, Rscratch3, 4*K);
+ __ blt(CCR0, Lskip_stack_check);
+
+ DEBUG_ONLY(__ untested("stack overflow check during monitor enter");)
+ __ li(Rscratch1, 0);
+ __ generate_stack_overflow_check_with_compare_and_throw(Rscratch1, Rscratch2);
+
+ __ align(32, 12);
+ __ bind(Lskip_stack_check);
+
+ // The bcp has already been incremented. Just need to dispatch to next instruction.
+ __ dispatch_next(vtos);
+}
+
+void TemplateTable::monitorexit() {
+ transition(atos, vtos);
+ __ verify_oop(R17_tos);
+
+ Register Rcurrent_monitor = R11_scratch1,
+ Rcurrent_obj = R12_scratch2,
+ Robj_to_lock = R17_tos,
+ Rcurrent_obj_addr = R3_ARG1,
+ Rlimit = R4_ARG2;
+ Label Lfound, Lillegal_monitor_state;
+
+ // Check corner case: unbalanced monitorEnter / Exit.
+ __ ld(Rlimit, 0, R1_SP);
+ __ addi(Rlimit, Rlimit, - (frame::ijava_state_size + frame::interpreter_frame_monitor_size_in_bytes())); // Monitor base
+
+ // Null pointer check.
+ __ null_check_throw(Robj_to_lock, -1, R11_scratch1);
+
+ __ cmpld(CCR0, R26_monitor, Rlimit);
+ __ bgt(CCR0, Lillegal_monitor_state);
+
+ // Find the corresponding slot in the monitors stack section.
+ {
+ Label Lloop;
+
+ // Start with topmost monitor.
+ __ addi(Rcurrent_obj_addr, R26_monitor, BasicObjectLock::obj_offset_in_bytes());
+ __ addi(Rlimit, Rlimit, BasicObjectLock::obj_offset_in_bytes());
+ __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize);
+
+ __ bind(Lloop);
+ // Is this entry for same obj?
+ __ cmpd(CCR0, Rcurrent_obj, Robj_to_lock);
+ __ beq(CCR0, Lfound);
+
+ // Check if last allocated BasicLockObj reached.
+
+ __ ld(Rcurrent_obj, 0, Rcurrent_obj_addr);
+ __ cmpld(CCR0, Rcurrent_obj_addr, Rlimit);
+ __ addi(Rcurrent_obj_addr, Rcurrent_obj_addr, frame::interpreter_frame_monitor_size() * wordSize);
+
+ // Next iteration if unchecked BasicObjectLocks exist on the stack.
+ __ ble(CCR0, Lloop);
+ }
+
+ // Fell through without finding the basic obj lock => throw up!
+ __ bind(Lillegal_monitor_state);
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
+ __ should_not_reach_here();
+
+ __ align(32, 12);
+ __ bind(Lfound);
+ __ addi(Rcurrent_monitor, Rcurrent_obj_addr,
+ -(frame::interpreter_frame_monitor_size() * wordSize) - BasicObjectLock::obj_offset_in_bytes());
+ __ unlock_object(Rcurrent_monitor);
+}
+
+// ============================================================================
+// Wide bytecodes
+
+// Wide instructions. Simply redirects to the wide entry point for that instruction.
+void TemplateTable::wide() {
+ transition(vtos, vtos);
+
+ const Register Rtable = R11_scratch1,
+ Rindex = R12_scratch2,
+ Rtmp = R0;
+
+ __ lbz(Rindex, 1, R14_bcp);
+
+ __ load_dispatch_table(Rtable, Interpreter::_wentry_point);
+
+ __ slwi(Rindex, Rindex, LogBytesPerWord);
+ __ ldx(Rtmp, Rtable, Rindex);
+ __ mtctr(Rtmp);
+ __ bctr();
+ // Note: the bcp increment step is part of the individual wide bytecode implementations.
+}
+#endif // !CC_INTERP
diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp
new file mode 100644
index 00000000000..1dfa8841c64
--- /dev/null
+++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, 2014 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP
+#define CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP
+
+ static void prepare_invoke(int byte_no, Register Rmethod, Register Rret_addr, Register Rindex, Register Rrecv, Register Rflags, Register Rscratch);
+ static void invokevfinal_helper(Register Rmethod, Register Rflags, Register Rscratch1, Register Rscratch2);
+ static void generate_vtable_call(Register Rrecv_klass, Register Rindex, Register Rret, Register Rtemp);
+ static void invokeinterface_object_method(Register Rrecv_klass, Register Rret, Register Rflags, Register Rindex, Register Rtemp, Register Rtemp2);
+
+ // Branch_conditional which takes TemplateTable::Condition.
+ static void branch_conditional(ConditionRegister crx, TemplateTable::Condition cc, Label& L, bool invert = false);
+ static void if_cmp_common(Register Rfirst, Register Rsecond, Register Rscratch1, Register Rscratch2, Condition cc, bool is_jint, bool cmp0);
+
+#endif // CPU_PPC_VM_TEMPLATETABLE_PPC_64_HPP
diff --git a/hotspot/src/share/vm/interpreter/templateTable.hpp b/hotspot/src/share/vm/interpreter/templateTable.hpp
index bb5169a6ccb..c6ea51537a2 100644
--- a/hotspot/src/share/vm/interpreter/templateTable.hpp
+++ b/hotspot/src/share/vm/interpreter/templateTable.hpp
@@ -376,6 +376,9 @@ class TemplateTable: AllStatic {
#ifdef TARGET_ARCH_MODEL_ppc_32
# include "templateTable_ppc_32.hpp"
#endif
+#ifdef TARGET_ARCH_MODEL_ppc_64
+# include "templateTable_ppc_64.hpp"
+#endif
};
#endif /* !CC_INTERP */
From 405bc140c090a1f20af6d630dbe8e46efb8c6347 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Tue, 11 Mar 2014 12:04:27 +0100
Subject: [PATCH 052/116] 8036965: 9-dev solaris builds failed: sort: can't
read STDIN: Illegal byte sequence
Reviewed-by: henryjen, tbell, ihse
---
make/common/JavaCompilation.gmk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index 5eed2ff701c..5ee8fdf301c 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -364,7 +364,7 @@ define add_file_to_clean
| $(SED) -e '/^#/d' -e '/^$$$$/d' \
-e :a -e '/\\$$$$/N; s/\\\n//; ta' \
-e 's/^[ \t]*//;s/[ \t]*$$$$//' \
- -e 's/\\=/=/' | LANG=C $(SORT) > $$@
+ -e 's/\\=/=/' | LC_ALL=C $(SORT) > $$@
$(CHMOD) -f ug+w $$@
# And do not forget this target
From 3cd6a66a8f1a55ab195384d7ddef2d4a83f29321 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Tue, 11 Mar 2014 12:04:50 +0100
Subject: [PATCH 053/116] 8036948: Solaris builds broken by fix for 8036611:
Cleanup of handling of properties ..
Reviewed-by: ihse
---
make/common/MakeBase.gmk | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 2b276c6f1fb..586d68ab937 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -380,11 +380,23 @@ ifeq ($(OPENJDK_TARGET_OS),solaris)
# On Solaris, if the target is a symlink and exists, cp won't overwrite.
# Cp has to operate in recursive mode to allow for -P flag, to preserve soft links. If the
# name of the target file differs from the source file, rename after copy.
+ # If the source and target parent directories are the same, recursive copy doesn't work
+ # so we fall back on regular copy, which isn't preserving symlinks.
define install-file
$(MKDIR) -p $(@D)
$(RM) '$@'
- $(CP) -f -r -P '$<' '$(@D)'
- if [ "$(@F)" != "$(
Date: Tue, 11 Mar 2014 15:03:26 -0700
Subject: [PATCH 054/116] Added tag jdk9-b04 for changeset 63e429dcac32
---
.hgtags-top-repo | 1 +
1 file changed, 1 insertion(+)
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 45398d20075..c1b1c04b6d6 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -246,3 +246,4 @@ cd3825b2983045784d6fc6d1729c799b08215752 jdk8-b120
50669e45cec4491de0d921d3118a3fe2e767020a jdk9-b01
135f0c7af57ebace31383d8877f47e32172759ff jdk9-b02
fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03
+cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04
From 8d93dcb8bc6e29ae68d33be77345e22e62fe772b Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:41:35 -0700
Subject: [PATCH 055/116] Added tag jdk9-b04 for changeset cf836c6f207d
---
corba/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/corba/.hgtags b/corba/.hgtags
index 13a64cfd8b1..e2c211437d6 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -246,3 +246,4 @@ a7d3638deb2f4e33217b1ecf889479e90f9e5b50 jdk9-b00
79a8136b18c1c6848f500088f5a4b39f262f082d jdk9-b01
8394993063135a42b63a94473280399fb2a13aa7 jdk9-b02
d338b892a13db19b093f85cf5f949a4504e4d31f jdk9-b03
+1ed19de263e1e0772da0269118cdd9deeb9fff04 jdk9-b04
From 6d3d6f745634719a6dfcfe8e6af35c4a00a476f9 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:41:45 -0700
Subject: [PATCH 056/116] Added tag jdk9-b04 for changeset 7a33ca900ff0
---
hotspot/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 71ad9311d10..7b77a830353 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -406,3 +406,4 @@ ce2d7e46f3c7e41241f3b407705a4071323a11ab jdk9-b00
050a626a88951140df874f7b163e304d07b6c296 jdk9-b01
b188446de75bda5fc52d102cddf242c3ef5ecbdf jdk9-b02
b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03
+3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04
From 09deb6906d7ff055e30a0fbeb4bbd89485e25a15 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:41:51 -0700
Subject: [PATCH 057/116] Added tag jdk9-b04 for changeset 4489a70abccd
---
jaxp/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index 89dfe4cfb54..235b496363e 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -246,3 +246,4 @@ e4e5069250e717defcb556e2f6be291460988c51 jdk8-b118
e5256f530a9b5f2d677ca245de44a617ffb58f52 jdk9-b01
02f60a253e15240087c043bad77a106792e4d56a jdk9-b02
fb92ed0399424193f444489ad49a16748816dc12 jdk9-b03
+2846d8fc31490897817a122a668af4f44fc913d0 jdk9-b04
From fe36912657aac4149d3a8afc7d9ab1f075e5e24a Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:41:53 -0700
Subject: [PATCH 058/116] Added tag jdk9-b04 for changeset c78b6c3c5e48
---
jaxws/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 8e843fe4b59..5de247bd72f 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -249,3 +249,4 @@ bc622ba563f9316f981c11c3a260f4c3fdc5ef07 jdk8-b122
9c9fabbcd3d526d7ca29165169155f49a107533a jdk9-b01
efe2bc258c78af49de9517a4a5699d3a2e630c44 jdk9-b02
1cd9786257ed4f82a3371fd606b162e5bb6fcd81 jdk9-b03
+da44a8bdf1f3fdd518e7d785d60cc1b15983b176 jdk9-b04
From 60774dc46b1a932c45d80cdf27282027a4a966b6 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:42:01 -0700
Subject: [PATCH 059/116] Added tag jdk9-b04 for changeset e16d4c844e76
---
jdk/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/jdk/.hgtags b/jdk/.hgtags
index 950784a2233..d4558dabdae 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -246,3 +246,4 @@ d31cd980e1da31fa496a359caaf1a165aeb5791a jdk8-b120
3b4ac8d1b76fc6bec9815f0ab714f15b552e4c7b jdk9-b01
8c8275426a3207d91393354f7a7f9bc362ec25cf jdk9-b02
4111af6151ed8ca8e3f5603c69729a68427e1d5b jdk9-b03
+627deed79b595a4789fc9151455b663a47381257 jdk9-b04
From 060f4862a7b94f0debdcbf0322e8f1e613820bd6 Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:42:05 -0700
Subject: [PATCH 060/116] Added tag jdk9-b04 for changeset 612191246a7d
---
langtools/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/langtools/.hgtags b/langtools/.hgtags
index ab6c1e2e32a..3dc1cdd6b60 100644
--- a/langtools/.hgtags
+++ b/langtools/.hgtags
@@ -246,3 +246,4 @@ afe63d41c699e0e2ee910ef20c41b60603c852a1 jdk9-b00
077c12d527fb5531c59666c1f84000fc1245a260 jdk9-b01
f2c58a337c8aaa1ce84dfa8a8e8c5d4c8c1e12fa jdk9-b02
151222468d1d04ce6613d33efa3d45bfaf53e3e5 jdk9-b03
+fa2ec6b6b1697ae4a78b03b609664dc6b47dee86 jdk9-b04
From bcc0d72114ad0270e1f2bb370617899d835fe5fe Mon Sep 17 00:00:00 2001
From: David Katleman
Date: Tue, 11 Mar 2014 15:42:07 -0700
Subject: [PATCH 061/116] Added tag jdk9-b04 for changeset 7825ce9a8228
---
nashorn/.hgtags | 1 +
1 file changed, 1 insertion(+)
diff --git a/nashorn/.hgtags b/nashorn/.hgtags
index f2335745fca..6e7c8e3a43d 100644
--- a/nashorn/.hgtags
+++ b/nashorn/.hgtags
@@ -237,3 +237,4 @@ c3343930c73c58a22c1d58719bb988aeb25a871f jdk8-b119
65347535840f045f2cd4341d7466c51009b1b06f jdk9-b01
b3517e51f40477f10db8bc30a557aa0ea712c274 jdk9-b02
832f89ff25d903c45cfc994553f1ade8821a4398 jdk9-b03
+3f6ef92cd7823372c45e79125adba4cbf1c9f7b2 jdk9-b04
From 07cc98bb1a8a5de32ee9c4fc39d5f3fd15121dea Mon Sep 17 00:00:00 2001
From: Joe Darcy
Date: Tue, 11 Mar 2014 17:52:45 -0700
Subject: [PATCH 062/116] 8037120: Fix doclint warnings in javax.lang.model
exception types
Reviewed-by: jjg
---
.../javax/lang/model/type/MirroredTypeException.java | 6 +++++-
.../javax/lang/model/type/MirroredTypesException.java | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java b/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java
index fd79f04e62d..21af5070a76 100644
--- a/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java
+++ b/langtools/src/share/classes/javax/lang/model/type/MirroredTypeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -70,6 +70,10 @@ public class MirroredTypeException extends MirroredTypesException {
/**
* Explicitly set all transient fields.
+ * @param s the serial stream
+ * @throws ClassNotFoundException for a missing class during
+ * deserialization
+ * @throws IOException for an IO problem during deserialization
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
diff --git a/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java b/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java
index e385241a378..2cff3ffdaf6 100644
--- a/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java
+++ b/langtools/src/share/classes/javax/lang/model/type/MirroredTypesException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -85,6 +85,10 @@ public class MirroredTypesException extends RuntimeException {
/**
* Explicitly set all transient fields.
+ * @param s the serial stream
+ * @throws ClassNotFoundException for a missing class during
+ * deserialization
+ * @throws IOException for an IO problem during deserialization
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
From 5c683d18a4d7e5868f0e1480626054481d4f8a48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?=
Date: Wed, 12 Mar 2014 11:26:00 +0100
Subject: [PATCH 063/116] 8021350: Share script classes between threads/globals
within context
Reviewed-by: lagergren, sundar
---
nashorn/make/build.xml | 4 +
nashorn/make/project.properties | 2 +-
.../jdk/nashorn/internal/codegen/Attr.java | 9 +-
.../internal/codegen/CodeGenerator.java | 4 +-
.../internal/codegen/SharedScopeCall.java | 2 +-
.../jdk/nashorn/internal/ir/FunctionNode.java | 16 +-
.../jdk/nashorn/internal/objects/Global.java | 73 +---
.../internal/objects/NativeBoolean.java | 17 +-
.../internal/objects/NativeJSAdapter.java | 4 +-
.../internal/objects/NativeNumber.java | 17 +-
.../internal/objects/NativeString.java | 17 +-
.../internal/objects/ScriptFunctionImpl.java | 22 +-
.../jdk/nashorn/internal/parser/Parser.java | 1 +
.../internal/runtime/AccessorProperty.java | 12 +-
.../jdk/nashorn/internal/runtime/Context.java | 88 ++++-
.../runtime/FinalScriptFunctionData.java | 30 +-
.../internal/runtime/GlobalObject.java | 16 -
.../nashorn/internal/runtime/Property.java | 16 +-
.../RecompilableScriptFunctionData.java | 84 +++--
.../internal/runtime/ScriptFunction.java | 46 +--
.../internal/runtime/ScriptFunctionData.java | 71 ++--
.../internal/runtime/ScriptObject.java | 79 +++--
.../internal/runtime/SetMethodCreator.java | 22 +-
.../nashorn/internal/runtime/WithObject.java | 7 +-
.../runtime/linker/NashornGuards.java | 60 ++++
.../runtime/linker/PrimitiveLookup.java | 25 +-
.../jdk/nashorn/api/scripting/ScopeTest.java | 316 ++++++++++++++++++
.../nashorn/api/scripting/resources/func.js | 42 +++
.../api/scripting/resources/gettersetter.js | 38 +++
.../api/scripting/resources/witheval.js | 60 ++++
30 files changed, 902 insertions(+), 298 deletions(-)
create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js
create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js
create mode 100644 nashorn/test/src/jdk/nashorn/api/scripting/resources/witheval.js
diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml
index 78a713bfc46..a33e355ce91 100644
--- a/nashorn/make/build.xml
+++ b/nashorn/make/build.xml
@@ -253,6 +253,10 @@
+
+
+
+
diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties
index d51e72e4180..5af728794e2 100644
--- a/nashorn/make/project.properties
+++ b/nashorn/make/project.properties
@@ -206,7 +206,7 @@ test262-test-sys-prop.test.failed.list.file=${build.dir}/test/failedTests
# test262 test frameworks
test262-test-sys-prop.test.js.framework=\
- --class-cache-size=0 \
+ --class-cache-size=10 \
--no-java \
--no-typed-arrays \
-timezone=PST \
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java
index 177cfef4e4b..61ccb712772 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java
@@ -375,10 +375,11 @@ final class Attr extends NodeOperatorVisitor {
* @return Symbol for given name or null for redefinition.
*/
private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) {
- int flags = symbolFlags;
- Symbol symbol = findSymbol(block, name); // Locate symbol.
+ int flags = symbolFlags;
+ Symbol symbol = findSymbol(block, name); // Locate symbol.
+ boolean isGlobal = (flags & KINDMASK) == IS_GLOBAL;
- if ((flags & KINDMASK) == IS_GLOBAL) {
+ if (isGlobal) {
flags |= IS_SCOPE;
}
@@ -414,6 +415,8 @@ final class Attr extends NodeOperatorVisitor {
// Determine where to create it.
if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
symbolBlock = block; //internal vars are always defined in the block closest to them
+ } else if (isGlobal) {
+ symbolBlock = lc.getOutermostFunction().getBody();
} else {
symbolBlock = lc.getFunctionBody(function);
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index 6ad92829bfe..e0ca67a4a92 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -685,7 +685,7 @@ final class CodeGenerator extends NodeOperatorVisitor 0) {
- classCache = new ClassCache(cacheSize);
- }
}
/**
@@ -488,7 +477,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Override
public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
- return new ScriptFunctionImpl(name, handle, scope, null, strict, false, true);
+ return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
}
@Override
@@ -664,62 +653,6 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
}
- /**
- * Cache for compiled script classes.
- */
- @SuppressWarnings("serial")
- private static class ClassCache extends LinkedHashMap {
- private final int size;
- private final ReferenceQueue> queue;
-
- ClassCache(int size) {
- super(size, 0.75f, true);
- this.size = size;
- this.queue = new ReferenceQueue<>();
- }
-
- void cache(final Source source, final Class> clazz) {
- put(source, new ClassReference(clazz, queue, source));
- }
-
- @Override
- protected boolean removeEldestEntry(final Map.Entry eldest) {
- return size() > size;
- }
-
- @Override
- public ClassReference get(Object key) {
- for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
- remove(ref.source);
- }
- return super.get(key);
- }
-
- }
-
- private static class ClassReference extends SoftReference> {
- private final Source source;
-
- ClassReference(final Class> clazz, final ReferenceQueue> queue, final Source source) {
- super(clazz, queue);
- this.source = source;
- }
- }
-
- // Class cache management
- @Override
- public Class> findCachedClass(final Source source) {
- assert classCache != null : "Class cache used without being initialized";
- ClassReference ref = classCache.get(source);
- return ref != null ? ref.get() : null;
- }
-
- @Override
- public void cacheClass(final Source source, final Class> clazz) {
- assert classCache != null : "Class cache used without being initialized";
- classCache.cache(source, clazz);
- }
-
private static T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) {
final T obj = map.get(key);
if (obj != null) {
@@ -1838,7 +1771,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
// use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
- this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, false, false, false);
+ this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0);
typeErrorThrower.setPrototype(UNDEFINED);
// Non-constructor built-in functions do not have "prototype" property
typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
index bd955079830..bde6c608519 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
@@ -30,6 +30,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -50,7 +51,10 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
public final class NativeBoolean extends ScriptObject {
private final boolean value;
- final static MethodHandle WRAPFILTER = findWrapFilter();
+ // Method handle to create an object wrapper for a primitive boolean
+ private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeBoolean.class, Object.class));
+ // Method handle to retrieve the Boolean prototype object
+ private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -164,7 +168,7 @@ public final class NativeBoolean extends ScriptObject {
* @return Link to be invoked at call site.
*/
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
- return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER);
+ return PrimitiveLookup.lookupPrimitive(request, Boolean.class, new NativeBoolean((Boolean)receiver), WRAPFILTER, PROTOFILTER);
}
/**
@@ -178,7 +182,12 @@ public final class NativeBoolean extends ScriptObject {
return new NativeBoolean((Boolean)receiver);
}
- private static MethodHandle findWrapFilter() {
- return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, "wrapFilter", MH.type(NativeBoolean.class, Object.class));
+ @SuppressWarnings("unused")
+ private static Object protoFilter(final Object object) {
+ return Global.instance().getBooleanPrototype();
+ }
+
+ private static MethodHandle findOwnMH(final String name, final MethodType type) {
+ return MH.findStatic(MethodHandles.lookup(), NativeBoolean.class, name, type);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index c77b2fe0fa9..ed879dc69b5 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -622,7 +622,7 @@ public final class NativeJSAdapter extends ScriptObject {
case "getMethod":
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
- final Object value = getObjectValue(find);
+ final Object value = find.getObjectValue();
if (value instanceof ScriptFunction) {
final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
// TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
@@ -691,7 +691,7 @@ public final class NativeJSAdapter extends ScriptObject {
final MethodType type = desc.getMethodType();
if (findData != null) {
final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
- final Object value = getObjectValue(findData);
+ final Object value = findData.getObjectValue();
if (value instanceof ScriptFunction) {
final ScriptFunction func = (ScriptFunction)value;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
index 09289a015d0..02d9b99efdc 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
@@ -34,6 +34,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.text.NumberFormat;
import java.util.Locale;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -57,7 +58,10 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
@ScriptClass("Number")
public final class NativeNumber extends ScriptObject {
- static final MethodHandle WRAPFILTER = findWrapFilter();
+ // Method handle to create an object wrapper for a primitive number
+ private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeNumber.class, Object.class));
+ // Method handle to retrieve the Number prototype object
+ private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
/** ECMA 15.7.3.2 largest positive finite value */
@Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT, where = Where.CONSTRUCTOR)
@@ -322,7 +326,7 @@ public final class NativeNumber extends ScriptObject {
* @return Link to be invoked at call site.
*/
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
- return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER);
+ return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER);
}
@SuppressWarnings("unused")
@@ -330,6 +334,11 @@ public final class NativeNumber extends ScriptObject {
return new NativeNumber(((Number)receiver).doubleValue());
}
+ @SuppressWarnings("unused")
+ private static Object protoFilter(final Object object) {
+ return Global.instance().getNumberPrototype();
+ }
+
private static double getNumberValue(final Object self) {
if (self instanceof Number) {
return ((Number)self).doubleValue();
@@ -378,7 +387,7 @@ public final class NativeNumber extends ScriptObject {
return str;
}
- private static MethodHandle findWrapFilter() {
- return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, "wrapFilter", MH.type(NativeNumber.class, Object.class));
+ private static MethodHandle findOwnMH(final String name, final MethodType type) {
+ return MH.findStatic(MethodHandles.lookup(), NativeNumber.class, name, type);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
index 2370f514518..53ae9a23004 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
@@ -32,6 +32,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
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.Arrays;
@@ -69,7 +70,10 @@ public final class NativeString extends ScriptObject {
private final CharSequence value;
- static final MethodHandle WRAPFILTER = findWrapFilter();
+ // Method handle to create an object wrapper for a primitive string
+ private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeString.class, Object.class));
+ // Method handle to retrieve the String prototype object
+ private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -1199,7 +1203,7 @@ public final class NativeString extends ScriptObject {
*/
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class);
- return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER);
+ return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER);
}
@SuppressWarnings("unused")
@@ -1207,6 +1211,11 @@ public final class NativeString extends ScriptObject {
return new NativeString((CharSequence)receiver);
}
+ @SuppressWarnings("unused")
+ private static Object protoFilter(final Object object) {
+ return Global.instance().getStringPrototype();
+ }
+
private static CharSequence getCharSequence(final Object self) {
if (self instanceof String || self instanceof ConsString) {
return (CharSequence)self;
@@ -1254,7 +1263,7 @@ public final class NativeString extends ScriptObject {
return key >= 0 && key < value.length();
}
- private static MethodHandle findWrapFilter() {
- return MH.findStatic(MethodHandles.lookup(), NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class));
+ private static MethodHandle findOwnMH(final String name, final MethodType type) {
+ return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index 9852c96273d..fe18be990b3 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -75,7 +75,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
private static final Object LAZY_PROTOTYPE = new Object();
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
- super(name, invokeHandle, getInitialMap(), null, specs, false, true, true);
+ super(name, invokeHandle, getInitialMap(), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -92,7 +92,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
- super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, false, true, true);
+ super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -109,8 +109,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
this(name, invokeHandle, map, specs, Global.instance());
}
- private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor, final Global global) {
- super(name, methodHandle, getMap(global, isStrict), scope, specs, isStrict, isBuiltin, isConstructor);
+ private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
+ super(name, methodHandle, getMap(global, isStrict(flags)), scope, specs, flags);
init(global);
}
@@ -121,12 +121,10 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param methodHandle handle for invocation
* @param scope scope object
* @param specs specialized versions of this method, if available, null otherwise
- * @param isStrict are we in strict mode
- * @param isBuiltin is this a built-in function
- * @param isConstructor can the function be used as a constructor (most can; some built-ins are restricted).
+ * @param flags {@link ScriptFunctionData} flags
*/
- ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- this(name, methodHandle, scope, specs, isStrict, isBuiltin, isConstructor, Global.instance());
+ ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) {
+ this(name, methodHandle, scope, specs, flags, Global.instance());
}
private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) {
@@ -173,6 +171,10 @@ public class ScriptFunctionImpl extends ScriptFunction {
return newMap;
}
+ private static boolean isStrict(final int flags) {
+ return (flags & ScriptFunctionData.IS_STRICT) != 0;
+ }
+
// Choose the map based on strict mode!
private static PropertyMap getMap(final Global global, final boolean strict) {
return strict ? getInitialStrictMap() : getInitialMap();
@@ -211,7 +213,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @return new ScriptFunction
*/
static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
- final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, false, true, false);
+ final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, ScriptFunctionData.IS_BUILTIN);
func.setPrototype(UNDEFINED);
// Non-constructor built-in functions do not have "prototype" property
func.deleteOwnProperty(func.getMap().findProperty("prototype"));
diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java
index 60cbaccb68e..f6b962a93e1 100644
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java
@@ -1799,6 +1799,7 @@ loop:
case THIS:
final String name = type.getName();
next();
+ lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
return new IdentNode(primaryToken, finish, name);
case IDENT:
final IdentNode ident = getIdent();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index 702ca76ba1f..d22a956760b 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -141,10 +141,12 @@ public final class AccessorProperty extends Property {
private Class> currentType;
/**
- * Delegate constructor. This is used when adding properties to the Global scope, which
- * is necessary for outermost levels in a script (the ScriptObject is represented by
- * a JO-prefixed ScriptObject class, but the properties need to be in the Global scope
- * and are thus rebound with that as receiver
+ * Delegate constructor for bound properties. This is used for properties created by
+ * {@link ScriptRuntime#mergeScope} and the Nashorn {@code Object.bindProperties} method.
+ * The former is used to add a script's defined globals to the current global scope while
+ * still storing them in a JO-prefixed ScriptObject class.
+ *
+ * All properties created by this constructor have the {@link #IS_BOUND} flag set.
*
* @param property accessor property to rebind
* @param delegate delegate object to rebind receiver to
@@ -157,6 +159,8 @@ public final class AccessorProperty extends Property {
this.objectGetter = bindTo(property.ensureObjectGetter(), delegate);
this.objectSetter = bindTo(property.ensureObjectSetter(), delegate);
+ // Properties created this way are bound to a delegate
+ this.flags |= IS_BOUND;
setCurrentType(property.getCurrentType());
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
index 3e6a1488fa3..51287affc71 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
@@ -36,6 +36,8 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
@@ -46,6 +48,7 @@ import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import jdk.internal.org.objectweb.asm.ClassReader;
@@ -155,6 +158,9 @@ public final class Context {
private static final ThreadLocal currentGlobal = new ThreadLocal<>();
+ // class cache
+ private ClassCache classCache;
+
/**
* Get the current global scope
* @return the current global scope
@@ -348,6 +354,11 @@ public final class Context {
this.classPathLoader = null;
}
+ final int cacheSize = env._class_cache_size;
+ if (cacheSize > 0) {
+ classCache = new ClassCache(cacheSize);
+ }
+
// print version info if asked.
if (env._version) {
getErr().println("nashorn " + Version.version());
@@ -659,7 +670,7 @@ public final class Context {
public static void checkPackageAccess(final String pkgName) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- checkPackageAccess(sm, pkgName.endsWith(".")? pkgName : pkgName + ".");
+ checkPackageAccess(sm, pkgName.endsWith(".") ? pkgName : pkgName + ".");
}
}
@@ -925,16 +936,10 @@ public final class Context {
// start with no errors, no warnings.
errMan.reset();
- GlobalObject global = null;
- Class> script;
-
- if (env._class_cache_size > 0) {
- global = (GlobalObject)Context.getGlobalTrusted();
- script = global.findCachedClass(source);
- if (script != null) {
- Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
- return script;
- }
+ Class> script = findCachedClass(source);
+ if (script != null) {
+ Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
+ return script;
}
final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
@@ -963,10 +968,7 @@ public final class Context {
final FunctionNode newFunctionNode = compiler.compile(functionNode);
script = compiler.install(newFunctionNode);
-
- if (global != null) {
- global.cacheClass(source, script);
- }
+ cacheClass(source, script);
return script;
}
@@ -988,4 +990,60 @@ public final class Context {
private long getUniqueScriptId() {
return uniqueScriptId.getAndIncrement();
}
+
+ /**
+ * Cache for compiled script classes.
+ */
+ @SuppressWarnings("serial")
+ private static class ClassCache extends LinkedHashMap {
+ private final int size;
+ private final ReferenceQueue> queue;
+
+ ClassCache(int size) {
+ super(size, 0.75f, true);
+ this.size = size;
+ this.queue = new ReferenceQueue<>();
+ }
+
+ void cache(final Source source, final Class> clazz) {
+ put(source, new ClassReference(clazz, queue, source));
+ }
+
+ @Override
+ protected boolean removeEldestEntry(final Map.Entry eldest) {
+ return size() > size;
+ }
+
+ @Override
+ public ClassReference get(Object key) {
+ for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
+ remove(ref.source);
+ }
+ return super.get(key);
+ }
+
+ }
+
+ private static class ClassReference extends SoftReference> {
+ private final Source source;
+
+ ClassReference(final Class> clazz, final ReferenceQueue> queue, final Source source) {
+ super(clazz, queue);
+ this.source = source;
+ }
+ }
+
+ // Class cache management
+ private Class> findCachedClass(final Source source) {
+ ClassReference ref = classCache == null ? null : classCache.get(source);
+ return ref != null ? ref.get() : null;
+ }
+
+ private void cacheClass(final Source source, final Class> clazz) {
+ if (classCache != null) {
+ classCache.cache(source, clazz);
+ }
+ }
+
+
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
index c7a410ea821..f16cf41c3ab 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -38,31 +38,27 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
/**
* Constructor - used for bind
*
- * @param name name
- * @param arity arity
- * @param functions precompiled code
- * @param isStrict strict
- * @param isBuiltin builtin
- * @param isConstructor constructor
+ * @param name name
+ * @param arity arity
+ * @param functions precompiled code
+ * @param flags {@link ScriptFunctionData} flags
*/
- FinalScriptFunctionData(final String name, int arity, CompiledFunctions functions, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- super(name, arity, isStrict, isBuiltin, isConstructor);
+ FinalScriptFunctionData(final String name, final int arity, final CompiledFunctions functions, final int flags) {
+ super(name, arity, flags);
code.addAll(functions);
}
/**
- * Constructor - used from ScriptFunction. This assumes that we have code alraedy for the
+ * Constructor - used from ScriptFunction. This assumes that we have code already for the
* method (typically a native method) and possibly specializations.
*
- * @param name name
- * @param mh method handle for generic version of method
- * @param specs specializations
- * @param isStrict strict
- * @param isBuiltin builtin
- * @param isConstructor constructor
+ * @param name name
+ * @param mh method handle for generic version of method
+ * @param specs specializations
+ * @param flags {@link ScriptFunctionData} flags
*/
- FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- super(name, arity(mh), isStrict, isBuiltin, isConstructor);
+ FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
+ super(name, arity(mh), flags);
addInvoker(mh);
if (specs != null) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
index 3779f3bda9c..20046388292 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
@@ -210,22 +210,6 @@ public interface GlobalObject {
*/
public Object getDefaultValue(ScriptObject sobj, Class> typeHint);
- /**
- * Find the compiled Class for the given script source, if available
- *
- * @param source Source object of the script
- * @return compiled Class object or null
- */
- public Class> findCachedClass(Source source);
-
- /**
- * Put the Source associated Class object in the Source-to-Class cache
- *
- * @param source Source of the script
- * @param clazz compiled Class object for the source
- */
- public void cacheClass(Source source, Class> clazz);
-
/**
* Get cached InvokeByName object for the given key
* @param key key to be associated with InvokeByName object
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
index d1dbe2adb4b..885fa712a13 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
@@ -84,9 +84,13 @@ public abstract class Property {
/** Can this property be undefined? */
public static final int CAN_BE_UNDEFINED = 1 << 8;
- /* Is this a function declaration property ? */
+ /** Is this a function declaration property ? */
public static final int IS_FUNCTION_DECLARATION = 1 << 9;
+ /** Is this property bound to a receiver? This means get/set operations will be delegated to
+ * a statically defined object instead of the object passed as callsite parameter. */
+ public static final int IS_BOUND = 1 << 10;
+
/** Property key. */
private final String key;
@@ -251,6 +255,16 @@ public abstract class Property {
return (flags & IS_SPILL) == IS_SPILL;
}
+ /**
+ * Is this property bound to a receiver? If this method returns {@code true} get and set operations
+ * will be delegated to a statically bound object instead of the object passed as parameter.
+ *
+ * @return true if this is a bound property
+ */
+ public boolean isBound() {
+ return (flags & IS_BOUND) == IS_BOUND;
+ }
+
/**
* Does this property use any slots in the spill array described in
* {@link Property#isSpill}? In that case how many. Currently a property
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index 2b18cbc87b6..7e1a516aa6d 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -103,9 +103,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
public RecompilableScriptFunctionData(final FunctionNode functionNode, final CodeInstaller installer, final String allocatorClassName, final PropertyMap allocatorMap) {
super(functionName(functionNode),
functionNode.getParameters().size(),
- functionNode.isStrict(),
- false,
- true);
+ getFlags(functionNode));
this.functionNode = functionNode;
this.source = functionNode.getSource();
@@ -129,10 +127,11 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
final StringBuilder sb = new StringBuilder();
if (source != null) {
- sb.append(source.getName())
- .append(':')
- .append(functionNode.getLineNumber())
- .append(' ');
+ sb.append(source.getName());
+ if (functionNode != null) {
+ sb.append(':').append(functionNode.getLineNumber());
+ }
+ sb.append(' ');
}
return sb.toString() + super.toString();
@@ -159,6 +158,20 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return Token.toDesc(TokenType.FUNCTION, position, length);
}
+ private static int getFlags(final FunctionNode functionNode) {
+ int flags = IS_CONSTRUCTOR;
+ if (functionNode.isStrict()) {
+ flags |= IS_STRICT;
+ }
+ if (functionNode.needsCallee()) {
+ flags |= NEEDS_CALLEE;
+ }
+ if (functionNode.usesThis() || functionNode.hasEval()) {
+ flags |= USES_THIS;
+ }
+ return flags;
+ }
+
@Override
ScriptObject allocate(final PropertyMap map) {
try {
@@ -182,41 +195,42 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData {
return allocatorMap;
}
+
+ @Override
+ protected void ensureCompiled() {
+ if (functionNode != null && functionNode.isLazy()) {
+ Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
+ final Compiler compiler = new Compiler(installer);
+ functionNode = compiler.compile(functionNode);
+ assert !functionNode.isLazy();
+ compiler.install(functionNode);
+ flags = getFlags(functionNode);
+ }
+ }
+
@Override
protected synchronized void ensureCodeGenerated() {
- if (!code.isEmpty()) {
- return; // nothing to do, we have code, at least some.
- }
+ if (!code.isEmpty()) {
+ return; // nothing to do, we have code, at least some.
+ }
- if (functionNode.isLazy()) {
- Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
- final Compiler compiler = new Compiler(installer);
- functionNode = compiler.compile(functionNode);
- assert !functionNode.isLazy();
- compiler.install(functionNode);
+ ensureCompiled();
- /*
- * We don't need to update any flags - varArgs and needsCallee are instrincic
- * in the function world we need to get a destination node from the compile instead
- * and replace it with our function node. TODO
- */
- }
+ /*
+ * We can't get to this program point unless we have bytecode, either from
+ * eager compilation or from running a lazy compile on the lines above
+ */
- /*
- * We can't get to this program point unless we have bytecode, either from
- * eager compilation or from running a lazy compile on the lines above
- */
+ assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
- assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode);
+ // code exists - look it up and add it into the automatically sorted invoker list
+ addCode(functionNode);
- // code exists - look it up and add it into the automatically sorted invoker list
- addCode(functionNode);
-
- if (! functionNode.canSpecialize()) {
- // allow GC to claim IR stuff that is not needed anymore
- functionNode = null;
- installer = null;
- }
+ if (! functionNode.canSpecialize()) {
+ // allow GC to claim IR stuff that is not needed anymore
+ functionNode = null;
+ installer = null;
+ }
}
private MethodHandle addCode(final FunctionNode fn) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index 0f5174ea15b..d0c6989b14a 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -66,6 +66,8 @@ public abstract class ScriptFunction extends ScriptObject {
private static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", Object.class, Object.class);
+ private static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class);
+
/** method handle to scope getter for this ScriptFunction */
public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
@@ -91,9 +93,7 @@ public abstract class ScriptFunction extends ScriptObject {
* @param map property map
* @param scope scope
* @param specs specialized version of this function - other method handles
- * @param strict is this a strict mode function?
- * @param builtin is this a built in function?
- * @param isConstructor is this a constructor?
+ * @param flags {@link ScriptFunctionData} flags
*/
protected ScriptFunction(
final String name,
@@ -101,11 +101,9 @@ public abstract class ScriptFunction extends ScriptObject {
final PropertyMap map,
final ScriptObject scope,
final MethodHandle[] specs,
- final boolean strict,
- final boolean builtin,
- final boolean isConstructor) {
+ final int flags) {
- this(new FinalScriptFunctionData(name, methodHandle, specs, strict, builtin, isConstructor), map, scope);
+ this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
}
/**
@@ -480,6 +478,13 @@ public abstract class ScriptFunction extends ScriptObject {
return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
}
+
+ @SuppressWarnings("unused")
+ private static Object globalFilter(final Object object) {
+ // replace whatever we get with the current global object
+ return Context.getGlobalTrusted();
+ }
+
/**
* dyn:call call site signature: (callee, thiz, [args...])
* generated method signature: (callee, thiz, [args...])
@@ -495,11 +500,11 @@ public abstract class ScriptFunction extends ScriptObject {
@Override
protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType type = desc.getMethodType();
+ final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
if (request.isCallSiteUnstable()) {
- // (this, callee, args...) => (this, callee, args[])
- final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class,
- type.parameterCount() - 2);
+ // (callee, this, args...) => (callee, this, args[])
+ final MethodHandle collector = MH.asCollector(ScriptRuntime.APPLY.methodHandle(), Object[].class, type.parameterCount() - 2);
// If call site is statically typed to take a ScriptFunction, we don't need a guard, otherwise we need a
// generic "is this a ScriptFunction?" guard.
@@ -510,17 +515,12 @@ public abstract class ScriptFunction extends ScriptObject {
MethodHandle boundHandle;
MethodHandle guard = null;
- final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
-
if (data.needsCallee()) {
final MethodHandle callHandle = getBestInvoker(type, request.getArguments());
- if (scopeCall) {
+ if (scopeCall && needsWrappedThis()) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
- // (callee, this, args...) => (callee, args...)
- boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
- // (callee, args...) => (callee, [this], args...)
- boundHandle = MH.dropArguments(boundHandle, 1, Object.class);
-
+ // (callee, this, args...) => (callee, [this], args...)
+ boundHandle = MH.filterArguments(callHandle, 1, GLOBALFILTER);
} else {
// It's already (callee, this, args...), just what we need
boundHandle = callHandle;
@@ -531,12 +531,12 @@ public abstract class ScriptFunction extends ScriptObject {
// NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
// current lookup as its "this" so it can do security-sensitive creation of adapter classes.
boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, Object.class, Object.class);
- } else if (scopeCall) {
+ } else if (scopeCall && needsWrappedThis()) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
- // (this, args...) => (args...)
- boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED);
- // (args...) => ([callee], [this], args...)
- boundHandle = MH.dropArguments(boundHandle, 0, Object.class, Object.class);
+ // (this, args...) => ([this], args...)
+ boundHandle = MH.filterArguments(callHandle, 0, GLOBALFILTER);
+ // ([this], args...) => ([callee], [this], args...)
+ boundHandle = MH.dropArguments(boundHandle, 0, Object.class);
} else {
// (this, args...) => ([callee], this, args...)
boundHandle = MH.dropArguments(callHandle, 0, Object.class);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index f0569937dd0..de39449b81b 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -47,33 +47,44 @@ public abstract class ScriptFunctionData {
/** All versions of this function that have been generated to code */
protected final CompiledFunctions code;
+ /** Function flags */
+ protected int flags;
+
private int arity;
- private final boolean isStrict;
-
- private final boolean isBuiltin;
-
- private final boolean isConstructor;
-
private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
+ /** Is this a strict mode function? */
+ public static final int IS_STRICT = 1 << 0;
+ /** Is this a built-in function? */
+ public static final int IS_BUILTIN = 1 << 1;
+ /** Is this a constructor function? */
+ public static final int IS_CONSTRUCTOR = 1 << 2;
+ /** Does this function expect a callee argument? */
+ public static final int NEEDS_CALLEE = 1 << 3;
+ /** Does this function make use of the this-object argument? */
+ public static final int USES_THIS = 1 << 4;
+
+ /** Flag for strict or built-in functions */
+ public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN;
+ /** Flag for built-in constructors */
+ public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR;
+ /** Flag for strict constructors */
+ public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR;
+
/**
* Constructor
*
* @param name script function name
* @param arity arity
- * @param isStrict is the function strict
- * @param isBuiltin is the function built in
- * @param isConstructor is the function a constructor
+ * @param flags the function flags
*/
- ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
- this.name = name;
- this.arity = arity;
- this.code = new CompiledFunctions();
- this.isStrict = isStrict;
- this.isBuiltin = isBuiltin;
- this.isConstructor = isConstructor;
+ ScriptFunctionData(final String name, final int arity, final int flags) {
+ this.name = name;
+ this.arity = arity;
+ this.code = new CompiledFunctions();
+ this.flags = flags;
}
final int getArity() {
@@ -105,21 +116,21 @@ public abstract class ScriptFunctionData {
* @return true if strict, false otherwise
*/
public boolean isStrict() {
- return isStrict;
+ return (flags & IS_STRICT) != 0;
}
boolean isBuiltin() {
- return isBuiltin;
+ return (flags & IS_BUILTIN) != 0;
}
boolean isConstructor() {
- return isConstructor;
+ return (flags & IS_CONSTRUCTOR) != 0;
}
boolean needsCallee() {
- // we don't know if we need a callee or not unless we are generated
- ensureCodeGenerated();
- return code.needsCallee();
+ // we don't know if we need a callee or not unless code has been compiled
+ ensureCompiled();
+ return (flags & NEEDS_CALLEE) != 0;
}
/**
@@ -128,7 +139,7 @@ public abstract class ScriptFunctionData {
* @return true if this argument must be an object
*/
boolean needsWrappedThis() {
- return !isStrict && !isBuiltin;
+ return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
}
String toSource() {
@@ -201,6 +212,15 @@ public abstract class ScriptFunctionData {
//empty
}
+ /**
+ * If we can have lazy code generation, this is a hook to ensure that the code has been compiled.
+ * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance;
+ * use {@link #ensureCodeGenerated()} to install the actual method handles.
+ */
+ protected void ensureCompiled() {
+ //empty
+ }
+
/**
* Return a generic Object/Object invoker for this method. It will ensure code
* is generated, get the most generic of all versions of this function and adapt it
@@ -259,6 +279,8 @@ public abstract class ScriptFunctionData {
final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
final int length = args == null ? 0 : args.length;
+ // Clear the callee and this flags
+ final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS;
CompiledFunctions boundList = new CompiledFunctions();
if (code.size() == 1) {
@@ -273,8 +295,7 @@ public abstract class ScriptFunctionData {
boundList.add(bind(inv, fn, self, allArgs));
}
- ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
- return boundData;
+ return new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, boundFlags);
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
index b7f9c4c1ed0..4696bdeacad 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -66,6 +66,7 @@ import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.objects.AccessorPropertyDescriptor;
import jdk.nashorn.internal.objects.DataPropertyDescriptor;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -131,7 +132,8 @@ public abstract class ScriptObject implements PropertyAccess {
static final MethodHandle GETPROTO = findOwnMH("getProto", ScriptObject.class);
static final MethodHandle SETPROTOCHECK = findOwnMH("setProtoCheck", void.class, Object.class);
- static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class);
+ static final MethodHandle MEGAMORPHIC_GET = findOwnMH("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
+ static final MethodHandle GLOBALFILTER = findOwnMH("globalFilter", Object.class, Object.class);
static final MethodHandle SETFIELD = findOwnMH("setField", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, MethodHandle.class, Object.class, Object.class);
static final MethodHandle SETSPILL = findOwnMH("setSpill", void.class, CallSiteDescriptor.class, PropertyMap.class, PropertyMap.class, int.class, Object.class, Object.class);
@@ -225,6 +227,7 @@ public abstract class ScriptObject implements PropertyAccess {
final Property oldProp = newMap.findProperty(key);
if (oldProp == null) {
if (property instanceof UserAccessorProperty) {
+ // Note: we copy accessor functions to this object which is semantically different from binding.
final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
newMap = newMap.addPropertyNoHistory(prop);
} else {
@@ -974,17 +977,6 @@ public abstract class ScriptObject implements PropertyAccess {
return ObjectClassGenerator.UNDEFINED_DOUBLE;
}
- /**
- * Get the object value of a property
- *
- * @param find {@link FindProperty} lookup result
- *
- * @return the value of the property
- */
- protected static Object getObjectValue(final FindProperty find) {
- return find.getObjectValue();
- }
-
/**
* Return methodHandle of value function for call.
*
@@ -995,7 +987,7 @@ public abstract class ScriptObject implements PropertyAccess {
* @return value of property as a MethodHandle or null.
*/
protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
- return getCallMethodHandle(getObjectValue(find), type, bindName);
+ return getCallMethodHandle(find.getObjectValue(), type, bindName);
}
/**
@@ -1019,7 +1011,7 @@ public abstract class ScriptObject implements PropertyAccess {
* @return Value of property.
*/
public final Object getWithProperty(final Property property) {
- return getObjectValue(new FindProperty(this, this, property));
+ return new FindProperty(this, this, property).getObjectValue();
}
/**
@@ -1740,7 +1732,7 @@ public abstract class ScriptObject implements PropertyAccess {
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
if (request.isCallSiteUnstable() || hasWithScope()) {
- return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
+ return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator), isScope() && NashornCallSiteDescriptor.isScope(desc));
}
final FindProperty find = findProperty(name, true);
@@ -1765,9 +1757,8 @@ public abstract class ScriptObject implements PropertyAccess {
final Property property = find.getProperty();
methodHandle = find.getGetter(returnType);
- final boolean noGuard = ObjectClassGenerator.OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
- // getMap() is fine as we have the prototype switchpoint depending on where the property was found
- final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
+ // Get the appropriate guard for this callsite and property.
+ final MethodHandle guard = NashornGuards.getGuard(this, property, desc);
final ScriptObject owner = find.getOwner();
if (methodHandle != null) {
@@ -1777,31 +1768,32 @@ public abstract class ScriptObject implements PropertyAccess {
}
if (!property.hasGetterFunction(owner)) {
- // If not a scope bind to actual prototype as changing prototype will change the property map.
- // For scopes we install a filter that replaces the self object with the prototype owning the property.
- methodHandle = isScope() ?
- addProtoFilter(methodHandle, find.getProtoChainLength()) :
- bindTo(methodHandle, owner);
+ // Add a filter that replaces the self object with the prototype owning the property.
+ methodHandle = addProtoFilter(methodHandle, find.getProtoChainLength());
}
- return new GuardedInvocation(methodHandle, noGuard ? null : getProtoSwitchPoint(name, owner), guard);
+ return new GuardedInvocation(methodHandle, guard == null ? null : getProtoSwitchPoint(name, owner), guard);
}
assert !NashornCallSiteDescriptor.isFastScope(desc);
return new GuardedInvocation(Lookup.emptyGetter(returnType), getProtoSwitchPoint(name, owner), guard);
}
- private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
- final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
+ private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name,
+ final boolean isMethod, final boolean isScope) {
+ final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, isScope);
final MethodHandle guard = getScriptObjectGuard(desc.getMethodType());
return new GuardedInvocation(invoker, guard);
}
@SuppressWarnings("unused")
- private Object megamorphicGet(final String key, final boolean isMethod) {
+ private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
final FindProperty find = findProperty(key, true);
if (find != null) {
- return getObjectValue(find);
+ return find.getObjectValue();
+ }
+ if (isScope) {
+ throw referenceError("not.defined", key);
}
return isMethod ? getNoSuchMethod(key) : invokeNoSuchProperty(key);
@@ -1996,6 +1988,15 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
+ @SuppressWarnings("unused")
+ private static Object globalFilter(final Object object) {
+ ScriptObject sobj = (ScriptObject) object;
+ while (sobj != null && !(sobj instanceof Global)) {
+ sobj = sobj.getProto();
+ }
+ return sobj;
+ }
+
private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
@@ -2041,7 +2042,7 @@ public abstract class ScriptObject implements PropertyAccess {
return noSuchProperty(desc, request);
}
- final Object value = getObjectValue(find);
+ final Object value = find.getObjectValue();
if (! (value instanceof ScriptFunction)) {
return createEmptyGetter(desc, name);
}
@@ -2067,7 +2068,7 @@ public abstract class ScriptObject implements PropertyAccess {
final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
if (find != null) {
- final Object value = getObjectValue(find);
+ final Object value = find.getObjectValue();
ScriptFunction func = null;
MethodHandle methodHandle = null;
@@ -2102,7 +2103,7 @@ public abstract class ScriptObject implements PropertyAccess {
final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
if (find != null) {
- final Object func = getObjectValue(find);
+ final Object func = find.getObjectValue();
if (func instanceof ScriptFunction) {
return ScriptRuntime.apply((ScriptFunction)func, this, name);
@@ -2124,7 +2125,7 @@ public abstract class ScriptObject implements PropertyAccess {
return invokeNoSuchProperty(name);
}
- final Object value = getObjectValue(find);
+ final Object value = find.getObjectValue();
if (! (value instanceof ScriptFunction)) {
return UNDEFINED;
}
@@ -2664,7 +2665,7 @@ public abstract class ScriptObject implements PropertyAccess {
final FindProperty find = object.findProperty(key, false, false, this);
if (find != null) {
- return getObjectValue(find);
+ return find.getObjectValue();
}
}
@@ -2682,7 +2683,7 @@ public abstract class ScriptObject implements PropertyAccess {
final FindProperty find = findProperty(key, true);
if (find != null) {
- return getObjectValue(find);
+ return find.getObjectValue();
}
}
@@ -2823,7 +2824,15 @@ public abstract class ScriptObject implements PropertyAccess {
throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
}
} else {
- spill(key, value);
+ ScriptObject sobj = this;
+ // undefined scope properties are set in the global object.
+ if (isScope()) {
+ while (sobj != null && !(sobj instanceof Global)) {
+ sobj = sobj.getProto();
+ }
+ assert sobj != null : "no parent global object in scope";
+ }
+ sobj.spill(key, value);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index bdbc8ec8b9a..2c01b6d3617 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -31,7 +31,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -104,21 +103,9 @@ final class SetMethodCreator {
* @return the composed guarded invocation that represents the dynamic setter method for the property.
*/
GuardedInvocation createGuardedInvocation() {
- return new GuardedInvocation(methodHandle, getGuard());
+ return new GuardedInvocation(methodHandle, NashornGuards.getGuard(sobj, property, desc));
}
- private MethodHandle getGuard() {
- return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap());
- }
-
- private boolean needsNoGuard() {
- return NashornCallSiteDescriptor.isFastScope(desc) &&
- (ObjectClassGenerator.OBJECT_FIELDS_ONLY || isPropertyTypeStable());
- }
-
- private boolean isPropertyTypeStable() {
- return property == null || !property.canChangeType();
- }
}
private SetMethod createSetMethod() {
@@ -153,10 +140,7 @@ final class SetMethodCreator {
final MethodHandle boundHandle;
if (!property.hasSetterFunction(find.getOwner()) && find.isInherited()) {
- // Bind or add prototype filter depending on whether this is a scope object.
- boundHandle = sobj.isScope() ?
- ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength()):
- ScriptObject.bindTo(methodHandle, find.getOwner());
+ boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
} else {
boundHandle = methodHandle;
}
@@ -165,7 +149,7 @@ final class SetMethodCreator {
private SetMethod createGlobalPropertySetter() {
final ScriptObject global = Context.getGlobalTrusted();
- return new SetMethod(ScriptObject.bindTo(global.addSpill(getName()), global), null);
+ return new SetMethod(MH.filterArguments(global.addSpill(getName()), 0, ScriptObject.GLOBALFILTER), null);
}
private SetMethod createNewPropertySetter() {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
index d4a28cd7fb4..dc48d727e48 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
@@ -88,6 +88,11 @@ public final class WithObject extends ScriptObject implements Scope {
@Override
public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
+ if (request.isCallSiteUnstable()) {
+ // Fall back to megamorphic invocation which performs a complete lookup each time without further relinking.
+ return super.lookup(desc, request);
+ }
+
// With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
// necessity have a Nashorn descriptor - it is safe to cast.
final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
@@ -265,7 +270,7 @@ public final class WithObject extends ScriptObject implements Scope {
}
private static MethodHandle filter(final MethodHandle mh, final MethodHandle filter) {
- return MH.filterArguments(mh, 0, filter);
+ return MH.filterArguments(mh, 0, filter.asType(filter.type().changeReturnType(mh.type().parameterType(0))));
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
index 0b720be2740..ca3e10c48d4 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java
@@ -29,6 +29,11 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.ref.WeakReference;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.nashorn.internal.codegen.ObjectClassGenerator;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -40,6 +45,7 @@ public final class NashornGuards {
private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class);
private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
+ private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class);
private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
// don't create me!
@@ -74,6 +80,55 @@ public final class NashornGuards {
return MH.insertArguments(IS_MAP, 1, map);
}
+ /**
+ * Determine whether the given callsite needs a guard.
+ * @param property the property, or null
+ * @param desc the callsite descriptor
+ * @return true if a guard should be used for this callsite
+ */
+ static boolean needsGuard(final Property property, final CallSiteDescriptor desc) {
+ return property == null || property.isConfigurable()
+ || property.isBound() || !ObjectClassGenerator.OBJECT_FIELDS_ONLY
+ || !NashornCallSiteDescriptor.isFastScope(desc) || property.canChangeType();
+ }
+
+ /**
+ * Get the guard for a property access. This returns an identity guard for non-configurable global properties
+ * and a map guard for everything else.
+ *
+ * @param sobj the first object in the prototype chain
+ * @param property the property
+ * @param desc the callsite descriptor
+ * @return method handle for guard
+ */
+ public static MethodHandle getGuard(final ScriptObject sobj, final Property property, final CallSiteDescriptor desc) {
+ if (!needsGuard(property, desc)) {
+ return null;
+ }
+ if (NashornCallSiteDescriptor.isScope(desc)) {
+ if (property != null && property.isBound()) {
+ // This is a declared top level variables in main script or eval, use identity guard.
+ return getIdentityGuard(sobj);
+ }
+ if (!(sobj instanceof Global) && (property == null || property.isConfigurable())) {
+ // Undeclared variables in nested evals need stronger guards
+ return combineGuards(getIdentityGuard(sobj), getMapGuard(sobj.getMap()));
+ }
+ }
+ return getMapGuard(sobj.getMap());
+ }
+
+
+ /**
+ * Get a guard that checks referential identity of the current object.
+ *
+ * @param sobj the self object
+ * @return true if same self object instance
+ */
+ public static MethodHandle getIdentityGuard(final ScriptObject sobj) {
+ return MH.insertArguments(SAME_OBJECT, 1, new WeakReference<>(sobj));
+ }
+
/**
* Get a guard that checks if in item is an instance of either of two classes.
*
@@ -111,6 +166,11 @@ public final class NashornGuards {
return self instanceof ScriptObject && ((ScriptObject)self).getMap() == map;
}
+ @SuppressWarnings("unused")
+ private static boolean sameObject(final Object self, final WeakReference ref) {
+ return self == ref.get();
+ }
+
@SuppressWarnings("unused")
private static boolean isInstanceOf2(final Object self, final Class> class1, final Class> class2) {
return class1.isInstance(self) || class2.isInstance(self);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
index c9b5eaa3fa9..7665be7fcb3 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
@@ -35,6 +35,7 @@ import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.ScriptObject;
/**
@@ -61,8 +62,9 @@ public final class PrimitiveLookup {
* type {@code receiverClass}.
*/
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Class> receiverClass,
- final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
- return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter);
+ final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
+ final MethodHandle protoFilter) {
+ return lookupPrimitive(request, Guards.getInstanceOfGuard(receiverClass), wrappedReceiver, wrapFilter, protoFilter);
}
/**
@@ -79,7 +81,8 @@ public final class PrimitiveLookup {
* type (that is implied by both {@code guard} and {@code wrappedReceiver}).
*/
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final MethodHandle guard,
- final ScriptObject wrappedReceiver, final MethodHandle wrapFilter) {
+ final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
+ final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
if ("setProp".equals(operator) || "setElem".equals(operator)) {
@@ -93,9 +96,23 @@ public final class PrimitiveLookup {
if(desc.getNameTokenCount() > 2) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- if(wrappedReceiver.findProperty(name, true) == null) {
+ final FindProperty find = wrappedReceiver.findProperty(name, true);
+ if(find == null) {
// Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
return null;
+ } else if (find.isInherited() && !find.getProperty().hasGetterFunction(find.getOwner())) {
+ // If property is found in the prototype object bind the method handle directly to
+ // the proto filter instead of going through wrapper instantiation below.
+ final ScriptObject proto = wrappedReceiver.getProto();
+ final GuardedInvocation link = proto.lookup(desc, request);
+
+ if (link != null) {
+ final MethodHandle invocation = link.getInvocation();
+ final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
+ final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
+ final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+ return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+ }
}
}
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
index a18055bb602..dc27d826402 100644
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScopeTest.java
@@ -245,4 +245,320 @@ public class ScopeTest {
sb.put("x", "newX");
assertTrue(e.eval("x", ctx).equals("newX"));
}
+
+ /**
+ * Test multi-threaded access to defined global variables for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedVarTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ final String sharedScript = "foo";
+
+ assertEquals(e.eval("var foo = 'original context';", origContext), null);
+ assertEquals(e.eval("var foo = 'new context';", newCtxt), null);
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ assertEquals(e.eval("var foo = 'newer context';", newCtxt), null);
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+
+ assertEquals(e.eval(sharedScript), "original context");
+ assertEquals(e.eval(sharedScript, newCtxt), "newer context");
+ }
+
+ /**
+ * Test multi-threaded access to undefined global variables for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedGlobalTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ assertEquals(e.eval("foo = 'original context';", origContext), "original context");
+ assertEquals(e.eval("foo = 'new context';", newCtxt), "new context");
+ final String sharedScript = "foo";
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ Object obj3 = e.eval("delete foo; foo = 'newer context';", newCtxt);
+ assertEquals(obj3, "newer context");
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+
+ Assert.assertEquals(e.eval(sharedScript), "original context");
+ Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
+ }
+
+ /**
+ * Test multi-threaded access using the postfix ++ operator for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedIncTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ assertEquals(e.eval("var x = 0;", origContext), null);
+ assertEquals(e.eval("var x = 2;", newCtxt), null);
+ final String sharedScript = "x++;";
+
+ final Thread t1 = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < 1000; i++) {
+ assertEquals(e.eval(sharedScript, origContext), (double)i);
+ }
+ } catch (ScriptException se) {
+ fail(se.toString());
+ }
+ }
+ });
+ final Thread t2 = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ for (int i = 2; i < 1000; i++) {
+ assertEquals(e.eval(sharedScript, newCtxt), (double)i);
+ }
+ } catch (ScriptException se) {
+ fail(se.toString());
+ }
+ }
+ });
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+ }
+
+ /**
+ * Test multi-threaded access to primitive prototype properties for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedPrimitiveTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ Object obj1 = e.eval("String.prototype.foo = 'original context';", origContext);
+ Object obj2 = e.eval("String.prototype.foo = 'new context';", newCtxt);
+ assertEquals(obj1, "original context");
+ assertEquals(obj2, "new context");
+ final String sharedScript = "''.foo";
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "new context", 1000));
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ Object obj3 = e.eval("delete String.prototype.foo; Object.prototype.foo = 'newer context';", newCtxt);
+ assertEquals(obj3, "newer context");
+ final Thread t3 = new Thread(new ScriptRunner(e, origContext, sharedScript, "original context", 1000));
+ final Thread t4 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, "newer context", 1000));
+
+ t3.start();
+ t4.start();
+ t3.join();
+ t4.join();
+
+ Assert.assertEquals(e.eval(sharedScript), "original context");
+ Assert.assertEquals(e.eval(sharedScript, newCtxt), "newer context");
+ }
+
+ /**
+ * Test multi-threaded scope function invocation for shared script classes with multiple globals.
+ */
+ @Test
+ public static void multiThreadedFunctionTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), origContext);
+ assertEquals(origContext.getAttribute("scopeVar"), 1);
+ assertEquals(e.eval("scopeTest()"), 1);
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/func.js")), newCtxt);
+ assertEquals(newCtxt.getAttribute("scopeVar"), 1);
+ assertEquals(e.eval("scopeTest();", newCtxt), 1);
+
+ assertEquals(e.eval("scopeVar = 3;", newCtxt), 3);
+ assertEquals(newCtxt.getAttribute("scopeVar"), 3);
+
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, "scopeTest()", 1, 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, "scopeTest()", 3, 1000));
+
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ }
+
+ /**
+ * Test multi-threaded access to global getters and setters for shared script classes with multiple globals.
+ */
+ @Test
+ public static void getterSetterTest() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ final String sharedScript = "accessor1";
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext);
+ assertEquals(e.eval("accessor1 = 1;"), 1);
+ assertEquals(e.eval(sharedScript), 1);
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt);
+ assertEquals(e.eval("accessor1 = 2;", newCtxt), 2);
+ assertEquals(e.eval(sharedScript, newCtxt), 2);
+
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000));
+
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ assertEquals(e.eval(sharedScript), 1);
+ assertEquals(e.eval(sharedScript, newCtxt), 2);
+ assertEquals(e.eval("v"), 1);
+ assertEquals(e.eval("v", newCtxt), 2);
+ }
+
+ /**
+ * Test multi-threaded access to global getters and setters for shared script classes with multiple globals.
+ */
+ @Test
+ public static void getterSetter2Test() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ final Bindings b = e.createBindings();
+ final ScriptContext origContext = e.getContext();
+ final ScriptContext newCtxt = new SimpleScriptContext();
+ newCtxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+ final String sharedScript = "accessor2";
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), origContext);
+ assertEquals(e.eval("accessor2 = 1;"), 1);
+ assertEquals(e.eval(sharedScript), 1);
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/gettersetter.js")), newCtxt);
+ assertEquals(e.eval("accessor2 = 2;", newCtxt), 2);
+ assertEquals(e.eval(sharedScript, newCtxt), 2);
+
+
+ final Thread t1 = new Thread(new ScriptRunner(e, origContext, sharedScript, 1, 1000));
+ final Thread t2 = new Thread(new ScriptRunner(e, newCtxt, sharedScript, 2, 1000));
+
+ t1.start();
+ t2.start();
+ t1.join();
+ t2.join();
+
+ assertEquals(e.eval(sharedScript), 1);
+ assertEquals(e.eval(sharedScript, newCtxt), 2);
+ assertEquals(e.eval("x"), 1);
+ assertEquals(e.eval("x", newCtxt), 2);
+ }
+
+ /**
+ * Test "slow" scopes involving {@code with} and {@code eval} statements for shared script classes with multiple globals.
+ */
+ @Test
+ public static void testSlowScope() throws ScriptException, InterruptedException {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+
+ for (int i = 0; i < 100; i++) {
+ final Bindings b = e.createBindings();
+ final ScriptContext ctxt = new SimpleScriptContext();
+ ctxt.setBindings(b, ScriptContext.ENGINE_SCOPE);
+
+ e.eval(new URLReader(ScopeTest.class.getResource("resources/witheval.js")), ctxt);
+ assertEquals(e.eval("a", ctxt), 1);
+ assertEquals(b.get("a"), 1);
+ assertEquals(e.eval("b", ctxt), 3);
+ assertEquals(b.get("b"), 3);
+ assertEquals(e.eval("c", ctxt), 10);
+ assertEquals(b.get("c"), 10);
+ }
+ }
+
+ private static class ScriptRunner implements Runnable {
+
+ final ScriptEngine engine;
+ final ScriptContext context;
+ final String source;
+ final Object expected;
+ final int iterations;
+
+ ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
+ this.engine = engine;
+ this.context = context;
+ this.source = source;
+ this.expected = expected;
+ this.iterations = iterations;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < iterations; i++) {
+ assertEquals(engine.eval(source, context), expected);
+ }
+ } catch (ScriptException se) {
+ throw new RuntimeException(se);
+ }
+ }
+ }
+
}
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js b/nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js
new file mode 100644
index 00000000000..477bd1a64be
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/resources/func.js
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
+
+var scopeVar = 1;
+var global = this;
+undefGlobal = this;
+
+function scopeTest() {
+ if (this !== global) {
+ throw new Error("this !== global");
+ }
+ if (this !== undefGlobal) {
+ throw new Error("this !== undefinedGlobal")
+ }
+ return scopeVar;
+}
+
+scopeTest();
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js b/nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js
new file mode 100644
index 00000000000..51e24727466
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/resources/gettersetter.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
+
+var v;
+
+Object.defineProperty(this, "accessor1", {
+ get: function() { return v; },
+ set: function(n) { v = n; }
+});
+
+Object.defineProperty(this, "accessor2", {
+ get: function() { return x; },
+ set: function(n) { x = n; }
+});
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/resources/witheval.js b/nashorn/test/src/jdk/nashorn/api/scripting/resources/witheval.js
new file mode 100644
index 00000000000..6041d5b4928
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/resources/witheval.js
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+// This script is loaded from jdk.nashorn.api.scripting.ScopeTest to test script class sharing and reuse.
+
+var a;
+
+function outer(p, e) {
+ eval(e);
+ with(p) {
+ function inner() {
+ a = 1;
+ c = 10;
+ if (a !== 1) {
+ throw new Error("a !== 1");
+ }
+ if (b !== 3) {
+ throw new Error("b !== 3");
+ }
+ if (c !== 10) {
+ throw new Error("c !== 10");
+ }
+ }
+ inner();
+ }
+}
+
+outer({}, "b = 3;");
+
+if (a !== 1) {
+ throw new Error("a !== 1");
+}
+if (b !== 3) {
+ throw new Error("b !== 3");
+}
+if (c !== 10) {
+ throw new Error("c !== 10");
+}
From 6f1436baa2dc8b91b82bb00b3296931f002f2bdf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?=
Date: Wed, 12 Mar 2014 16:33:28 +0100
Subject: [PATCH 064/116] 8034055: delete on global object not properly guarded
Reviewed-by: sundar, lagergren
---
nashorn/test/script/basic/JDK-8034055.js | 55 +++++++++++++++++++
.../test/script/basic/JDK-8034055.js.EXPECTED | 16 ++++++
2 files changed, 71 insertions(+)
create mode 100644 nashorn/test/script/basic/JDK-8034055.js
create mode 100644 nashorn/test/script/basic/JDK-8034055.js.EXPECTED
diff --git a/nashorn/test/script/basic/JDK-8034055.js b/nashorn/test/script/basic/JDK-8034055.js
new file mode 100644
index 00000000000..0a21d9f915a
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8034055.js
@@ -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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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-8034055: delete on global object not properly guarded
+ *
+ * @test
+ * @run
+ */
+
+
+var global = this;
+var x;
+
+function test(defineGlobals) {
+ if (defineGlobals) {
+ global.x = 1;
+ global.y = 2;
+ }
+ try {
+ print(x);
+ print(y);
+ } catch (e) {
+ print(e);
+ } finally {
+ print(delete global.x);
+ print(delete global.y);
+ }
+}
+
+// Repeatedly set and delete global variables
+test(true);
+test(false);
+test(true);
+test(false);
diff --git a/nashorn/test/script/basic/JDK-8034055.js.EXPECTED b/nashorn/test/script/basic/JDK-8034055.js.EXPECTED
new file mode 100644
index 00000000000..c947f4aeb23
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8034055.js.EXPECTED
@@ -0,0 +1,16 @@
+1
+2
+false
+true
+1
+ReferenceError: "y" is not defined
+false
+true
+1
+2
+false
+true
+1
+ReferenceError: "y" is not defined
+false
+true
From 572d5812621ede533953f482a94ebdc7533e1470 Mon Sep 17 00:00:00 2001
From: Athijegannathan Sundararajan
Date: Thu, 13 Mar 2014 15:58:24 +0530
Subject: [PATCH 065/116] 8015958: DataView constructor is not defined
Reviewed-by: attila, hannesw, lagergren
---
.../jdk/nashorn/internal/objects/Global.java | 11 +
.../internal/objects/NativeArrayBuffer.java | 13 +
.../internal/objects/NativeDataView.java | 1015 +++++++++++++++++
.../jdk/nashorn/internal/runtime/Context.java | 4 +-
.../runtime/resources/Messages.properties | 4 +
nashorn/test/script/basic/dataview_endian.js | 70 ++
nashorn/test/script/basic/dataview_getset.js | 93 ++
nashorn/test/script/basic/dataview_new.js | 71 ++
8 files changed, 1279 insertions(+), 2 deletions(-)
create mode 100644 nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
create mode 100644 nashorn/test/script/basic/dataview_endian.js
create mode 100644 nashorn/test/script/basic/dataview_getset.js
create mode 100644 nashorn/test/script/basic/dataview_new.js
diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java
index 82f2db4576b..0d8ac5caf6a 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java
@@ -226,6 +226,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
@Property(name = "ArrayBuffer", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object arrayBuffer;
+ /** DataView object */
+ @Property(name = "DataView", attributes = Attribute.NOT_ENUMERABLE)
+ public volatile Object dataView;
+
/** TypedArray (int8) */
@Property(name = "Int8Array", attributes = Attribute.NOT_ENUMERABLE)
public volatile Object int8Array;
@@ -352,6 +356,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private ScriptObject builtinJavaImporter;
private ScriptObject builtinJavaApi;
private ScriptObject builtinArrayBuffer;
+ private ScriptObject builtinDataView;
private ScriptObject builtinInt8Array;
private ScriptObject builtinUint8Array;
private ScriptObject builtinUint8ClampedArray;
@@ -866,6 +871,10 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return ScriptFunction.getPrototype(builtinArrayBuffer);
}
+ ScriptObject getDataViewPrototype() {
+ return ScriptFunction.getPrototype(builtinDataView);
+ }
+
ScriptObject getInt8ArrayPrototype() {
return ScriptFunction.getPrototype(builtinInt8Array);
}
@@ -1634,6 +1643,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private void initTypedArray() {
this.builtinArrayBuffer = initConstructor("ArrayBuffer");
+ this.builtinDataView = initConstructor("DataView");
this.builtinInt8Array = initConstructor("Int8Array");
this.builtinUint8Array = initConstructor("Uint8Array");
this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray");
@@ -1674,6 +1684,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
this.typeError = this.builtinTypeError;
this.uriError = this.builtinURIError;
this.arrayBuffer = this.builtinArrayBuffer;
+ this.dataView = this.builtinDataView;
this.int8Array = this.builtinInt8Array;
this.uint8Array = this.builtinUint8Array;
this.uint8ClampedArray = this.builtinUint8ClampedArray;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
index dbc1b24b2cb..49082498b57 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
@@ -25,6 +25,7 @@
package jdk.nashorn.internal.objects;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
@@ -128,4 +129,16 @@ final class NativeArrayBuffer extends ScriptObject {
public int getByteLength() {
return buffer.length;
}
+
+ ByteBuffer getBuffer() {
+ return ByteBuffer.wrap(buffer);
+ }
+
+ ByteBuffer getBuffer(final int offset) {
+ return ByteBuffer.wrap(buffer, offset, buffer.length - offset);
+ }
+
+ ByteBuffer getBuffer(final int offset, final int length) {
+ return ByteBuffer.wrap(buffer, offset, length);
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
new file mode 100644
index 00000000000..93b5f09f90c
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
@@ -0,0 +1,1015 @@
+/*
+ * Copyright (c) 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.objects;
+
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import jdk.nashorn.internal.objects.annotations.Attribute;
+import jdk.nashorn.internal.objects.annotations.Constructor;
+import jdk.nashorn.internal.objects.annotations.Function;
+import jdk.nashorn.internal.objects.annotations.Property;
+import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
+
+/**
+ *
+ * DataView builtin constructor. Based on the specification here:
+ * http://www.khronos.org/registry/typedarray/specs/latest/#8
+ *
+ *
+ * An ArrayBuffer is a useful object for representing an arbitrary chunk of data.
+ * In many cases, such data will be read from disk or from the network, and will
+ * not follow the alignment restrictions that are imposed on the typed array views
+ * described earlier. In addition, the data will often be heterogeneous in nature
+ * and have a defined byte order. The DataView view provides a low-level interface
+ * for reading such data from and writing it to an ArrayBuffer.
+ *
+ *
+ * Regardless of the host computer's endianness, DataView reads or writes values
+ * to or from main memory with a specified endianness: big or little.
+ *
+ */
+@ScriptClass("DataView")
+public class NativeDataView extends ScriptObject {
+ // initialized by nasgen
+ private static PropertyMap $nasgenmap$;
+
+ // inherited ArrayBufferView properties
+
+ /**
+ * Underlying ArrayBuffer storage object
+ */
+ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
+ public final Object buffer;
+
+ /**
+ * The offset in bytes from the start of the ArrayBuffer
+ */
+ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
+ public final int byteOffset;
+
+ /**
+ * The number of bytes from the offset that this DataView will reference
+ */
+ @Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
+ public final int byteLength;
+
+ // underlying ByteBuffer
+ private final ByteBuffer buf;
+
+ private NativeDataView(NativeArrayBuffer arrBuf) {
+ this(arrBuf, arrBuf.getBuffer(), 0);
+ }
+
+ private NativeDataView(NativeArrayBuffer arrBuf, int offset) {
+ this(arrBuf, bufferFrom(arrBuf, offset), offset);
+ }
+
+ private NativeDataView(NativeArrayBuffer arrBuf, int offset, int length) {
+ this(arrBuf, bufferFrom(arrBuf, offset, length), offset, length);
+ }
+
+ private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset) {
+ this(arrBuf, buf, offset, buf.capacity() - offset);
+ }
+
+ private NativeDataView(final NativeArrayBuffer arrBuf, final ByteBuffer buf, final int offset, final int length) {
+ super(Global.instance().getDataViewPrototype(), $nasgenmap$);
+ this.buffer = arrBuf;
+ this.byteOffset = offset;
+ this.byteLength = length;
+ this.buf = buf;
+ }
+
+ /**
+ * Create a new DataView object using the passed ArrayBuffer for its
+ * storage. Optional byteOffset and byteLength can be used to limit the
+ * section of the buffer referenced. The byteOffset indicates the offset in
+ * bytes from the start of the ArrayBuffer, and the byteLength is the number
+ * of bytes from the offset that this DataView will reference. If both
+ * byteOffset and byteLength are omitted, the DataView spans the entire
+ * ArrayBuffer range. If the byteLength is omitted, the DataView extends from
+ * the given byteOffset until the end of the ArrayBuffer.
+ *
+ * If the given byteOffset and byteLength references an area beyond the end
+ * of the ArrayBuffer an exception is raised.
+
+ * @param newObj if this constructor was invoked with 'new' or not
+ * @param self constructor function object
+ * @param args arguments to the constructor
+ * @return newly constructed DataView object
+ */
+ @Constructor(arity = 1)
+ public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+ if (args.length == 0 || !(args[0] instanceof NativeArrayBuffer)) {
+ throw typeError("not.an.arraybuffer.in.dataview");
+ }
+
+ final NativeArrayBuffer arrBuf = (NativeArrayBuffer) args[0];
+ switch (args.length) {
+ case 1:
+ return new NativeDataView(arrBuf);
+ case 2:
+ return new NativeDataView(arrBuf, JSType.toInt32(args[1]));
+ default:
+ return new NativeDataView(arrBuf, JSType.toInt32(args[1]), JSType.toInt32(args[2]));
+ }
+ }
+
+ /**
+ * Specialized version of DataView constructor
+ *
+ * @param newObj if this constructor was invoked with 'new' or not
+ * @param self constructor function object
+ * @param arrBuf underlying ArrayBuffer storage object
+ * @param offset offset in bytes from the start of the ArrayBuffer
+ * @return newly constructed DataView object
+ */
+ @SpecializedConstructor
+ public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) {
+ if (!(arrBuf instanceof NativeArrayBuffer)) {
+ throw typeError("not.an.arraybuffer.in.dataview");
+ }
+ return new NativeDataView((NativeArrayBuffer) arrBuf, offset);
+ }
+
+ /**
+ * Specialized version of DataView constructor
+ *
+ * @param newObj if this constructor was invoked with 'new' or not
+ * @param self constructor function object
+ * @param arrBuf underlying ArrayBuffer storage object
+ * @param offset in bytes from the start of the ArrayBuffer
+ * @param length is the number of bytes from the offset that this DataView will reference
+ * @return newly constructed DataView object
+ */
+ @SpecializedConstructor
+ public static Object constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) {
+ if (!(arrBuf instanceof NativeArrayBuffer)) {
+ throw typeError("not.an.arraybuffer.in.dataview");
+ }
+ return new NativeDataView((NativeArrayBuffer) arrBuf, offset, length);
+ }
+
+ // Gets the value of the given type at the specified byte offset
+ // from the start of the view. There is no alignment constraint;
+ // multi-byte values may be fetched from any offset.
+ //
+ // For multi-byte values, the optional littleEndian argument
+ // indicates whether a big-endian or little-endian value should be
+ // read. If false or undefined, a big-endian value is read.
+ //
+ // These methods raise an exception if they would read
+ // beyond the end of the view.
+
+ /**
+ * Get 8-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 8-bit signed int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static int getInt8(final Object self, final Object byteOffset) {
+ try {
+ return getBuffer(self).get(JSType.toInt32(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 8-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 8-bit signed int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getInt8(final Object self, final int byteOffset) {
+ try {
+ return getBuffer(self).get(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 8-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 8-bit unsigned int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE)
+ public static int getUint8(final Object self, final Object byteOffset) {
+ try {
+ return (0xFF & getBuffer(self).get(JSType.toInt32(byteOffset)));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 8-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 8-bit unsigned int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getUint8(final Object self, final int byteOffset) {
+ try {
+ return (0xFF & getBuffer(self).get(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 16-bit signed int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static int getInt16(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 16-bit signed int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getInt16(final Object self, final int byteOffset) {
+ try {
+ return getBuffer(self, false).getShort(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 16-bit signed int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getInt16(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getShort(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 16-bit unsigned int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static int getUint16(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(JSType.toInt32(byteOffset)));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 16-bit unsigned int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getUint16(final Object self, final int byteOffset) {
+ try {
+ return (int) (0xFFFF & getBuffer(self, false).getShort(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 16-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 16-bit unsigned int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getUint16(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return (int) (0xFFFF & getBuffer(self, littleEndian).getShort(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit signed int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static int getInt32(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 32-bit signed int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getInt32(final Object self, final int byteOffset) {
+ try {
+ return getBuffer(self, false).getInt(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit signed int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit signed int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static int getInt32(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getInt(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit unsigned int value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static long getUint32(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 32-bit unsigned int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static long getUint32(final Object self, final int byteOffset) {
+ try {
+ return (long) (0xFFFFFFFFL & getBuffer(self, false).getInt(JSType.toInt32(byteOffset)));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit unsigned int from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit unsigned int value at the byteOffset
+ */
+ @SpecializedFunction
+ public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return (long) (0xFFFFFFFFL & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit float value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static double getFloat32(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getFloat(JSType.toInt32(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 32-bit float value at the byteOffset
+ */
+ @SpecializedFunction
+ public static double getFloat32(final Object self, final int byteOffset) {
+ try {
+ return getBuffer(self, false).getFloat(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 32-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 32-bit float value at the byteOffset
+ */
+ @SpecializedFunction
+ public static double getFloat32(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getFloat(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 64-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 64-bit float value at the byteOffset
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
+ public static double getFloat64(final Object self, final Object byteOffset, final Object littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getDouble(JSType.toInt32(byteOffset));
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 64-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @return 64-bit float value at the byteOffset
+ */
+ @SpecializedFunction
+ public static double getFloat64(final Object self, final int byteOffset) {
+ try {
+ return getBuffer(self, false).getDouble(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Get 64-bit float value from given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param littleEndian (optional) flag indicating whether to read in little endian order
+ * @return 64-bit float value at the byteOffset
+ */
+ @SpecializedFunction
+ public static double getFloat64(final Object self, final int byteOffset, final boolean littleEndian) {
+ try {
+ return getBuffer(self, littleEndian).getDouble(byteOffset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ // Stores a value of the given type at the specified byte offset
+ // from the start of the view. There is no alignment constraint;
+ // multi-byte values may be stored at any offset.
+ //
+ // For multi-byte values, the optional littleEndian argument
+ // indicates whether the value should be stored in big-endian or
+ // little-endian byte order. If false or undefined, the value is
+ // stored in big-endian byte order.
+ //
+ // These methods raise an exception if they would write
+ // beyond the end of the view.
+
+ /**
+ * Set 8-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param value byte value to set
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setInt8(final Object self, final Object byteOffset, final Object value) {
+ try {
+ getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 8-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to read from
+ * @param value byte value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setInt8(final Object self, final int byteOffset, final int value) {
+ try {
+ getBuffer(self).put(byteOffset, (byte)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 8-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value byte value to set
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setUint8(final Object self, final Object byteOffset, final Object value) {
+ try {
+ getBuffer(self).put(JSType.toInt32(byteOffset), (byte)JSType.toInt32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 8-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value byte value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setUint8(final Object self, final int byteOffset, final int value) {
+ try {
+ getBuffer(self).put(byteOffset, (byte)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setInt16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setInt16(final Object self, final int byteOffset, final int value) {
+ try {
+ getBuffer(self, false).putShort(byteOffset, (short)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setInt16(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putShort(byteOffset, (short)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setUint16(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putShort(JSType.toInt32(byteOffset), (short)JSType.toInt32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setUint16(final Object self, final int byteOffset, final int value) {
+ try {
+ getBuffer(self, false).putShort(byteOffset, (short)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 16-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value short value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setUint16(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putShort(byteOffset, (short)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setInt32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toInt32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setInt32(final Object self, final int byteOffset, final int value) {
+ try {
+ getBuffer(self, false).putInt(byteOffset, value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit signed int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setInt32(final Object self, final int byteOffset, final int value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putInt(byteOffset, value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setUint32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putInt(JSType.toInt32(byteOffset), (int)JSType.toUint32(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setUint32(final Object self, final int byteOffset, final long value) {
+ try {
+ getBuffer(self, false).putInt(byteOffset, (int)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit unsigned int at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value int value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setUint32(final Object self, final int byteOffset, final long value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putInt(byteOffset, (int)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value float value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setFloat32(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putFloat((int)JSType.toUint32(byteOffset), (float)JSType.toNumber(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value float value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setFloat32(final Object self, final int byteOffset, final double value) {
+ try {
+ getBuffer(self, false).putFloat(byteOffset, (float)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 32-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value float value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setFloat32(final Object self, final int byteOffset, final double value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putFloat(byteOffset, (float)value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 64-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value double value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
+ public static Object setFloat64(final Object self, final Object byteOffset, final Object value, final Object littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putDouble((int)JSType.toUint32(byteOffset), JSType.toNumber(value));
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 64-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value double value to set
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setFloat64(final Object self, final int byteOffset, final double value) {
+ try {
+ getBuffer(self, false).putDouble(byteOffset, value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ /**
+ * Set 64-bit float at the given byteOffset
+ *
+ * @param self DataView object
+ * @param byteOffset byte offset to write at
+ * @param value double value to set
+ * @param littleEndian (optional) flag indicating whether to write in little endian order
+ * @return undefined
+ */
+ @SpecializedFunction
+ public static Object setFloat64(final Object self, final int byteOffset, final double value, final boolean littleEndian) {
+ try {
+ getBuffer(self, littleEndian).putDouble(byteOffset, value);
+ return UNDEFINED;
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.offset");
+ }
+ }
+
+ // internals only below this point
+ private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset) {
+ try {
+ return nab.getBuffer(offset);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.constructor.offset");
+ }
+ }
+
+ private static ByteBuffer bufferFrom(final NativeArrayBuffer nab, final int offset, final int length) {
+ try {
+ return nab.getBuffer(offset, length);
+ } catch (final IndexOutOfBoundsException ioe) {
+ throw rangeError(ioe, "dataview.constructor.offset");
+ }
+ }
+
+ private static NativeDataView checkSelf(final Object self) {
+ if (!(self instanceof NativeDataView)) {
+ throw typeError("not.an.arraybuffer", ScriptRuntime.safeToString(self));
+ }
+ return (NativeDataView)self;
+ }
+
+ private static ByteBuffer getBuffer(final Object self) {
+ return checkSelf(self).buf;
+ }
+
+ private static ByteBuffer getBuffer(final Object self, final Object littleEndian) {
+ return getBuffer(self, JSType.toBoolean(littleEndian));
+ }
+
+ private static ByteBuffer getBuffer(final Object self, final boolean littleEndian) {
+ return getBuffer(self).order(littleEndian? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
+ }
+}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
index 51287affc71..aaf9bbdd35d 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
@@ -648,7 +648,7 @@ public final class Context {
* Checks that the given Class can be accessed from no permissions context.
*
* @param clazz Class object
- * @throw SecurityException if not accessible
+ * @throws SecurityException if not accessible
*/
public static void checkPackageAccess(final Class> clazz) {
final SecurityManager sm = System.getSecurityManager();
@@ -665,7 +665,7 @@ public final class Context {
* Checks that the given package name can be accessed from no permissions context.
*
* @param pkgName package name
- * @throw SecurityException if not accessible
+ * @throws SecurityException if not accessible
*/
public static void checkPackageAccess(final String pkgName) {
final SecurityManager sm = System.getSecurityManager();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
index e1c4d1f1f8a..47248fce715 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -79,6 +79,7 @@ type.error.not.a.function={0} is not a function
type.error.not.a.constructor={0} is not a constructor function
type.error.not.a.file={0} is not a File
type.error.not.a.bytebuffer={0} is not a java.nio.ByteBuffer
+type.error.not.an.arraybuffer.in.dataview=First arg to DataView constructor must be an ArrayBuffer
# operations not permitted on undefined
type.error.cant.call.undefined=Cannot call undefined
@@ -137,6 +138,9 @@ type.error.no.method.matches.args=Can not invoke method {0} with the passed argu
type.error.method.not.constructor=Java method {0} can't be used as a constructor.
type.error.env.not.object=$ENV must be an Object.
type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
+
+range.error.dataview.constructor.offset=Wrong offset or length in DataView constructor
+range.error.dataview.offset=Offset is outside the bounds of the DataView
range.error.inappropriate.array.length=inappropriate array length: {0}
range.error.inappropriate.array.buffer.length=inappropriate array buffer length: {0}
range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20]
diff --git a/nashorn/test/script/basic/dataview_endian.js b/nashorn/test/script/basic/dataview_endian.js
new file mode 100644
index 00000000000..f7607c0ee05
--- /dev/null
+++ b/nashorn/test/script/basic/dataview_endian.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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-8015958: DataView constructor is not defined
+ *
+ * @test
+ * @run
+ */
+
+// set/get endianess checks
+
+var buffer = new ArrayBuffer(4);
+var dv = new DataView(buffer);
+
+// write (default) big endian, read big/little endian
+dv.setUint16(0, 0xABCD);
+Assert.assertEquals(dv.getUint16(0), 0xABCD);
+Assert.assertEquals(dv.getUint16(0, false), 0xABCD);
+Assert.assertEquals(dv.getUint16(0, true), 0xCDAB);
+
+// write little endian, read big/little endian
+dv.setUint16(0, 0xABCD, true);
+Assert.assertEquals(dv.getUint16(0), 0xCDAB);
+Assert.assertEquals(dv.getUint16(0, false), 0xCDAB);
+Assert.assertEquals(dv.getUint16(0, true), 0xABCD);
+
+// write explicit big endian, read big/little endian
+dv.setUint16(0, 0xABCD, false);
+Assert.assertEquals(dv.getUint16(0), 0xABCD);
+Assert.assertEquals(dv.getUint16(0, false), 0xABCD);
+Assert.assertEquals(dv.getUint16(0, true), 0xCDAB);
+
+// write (default) big endian, read big/little endian
+dv.setUint32(0, 0xABCDEF89);
+Assert.assertEquals(dv.getUint32(0), 0xABCDEF89);
+Assert.assertEquals(dv.getUint32(0, false), 0xABCDEF89);
+Assert.assertEquals(dv.getUint32(0, true), 0x89EFCDAB);
+
+// write little endian, read big/little endian
+dv.setUint32(0, 0xABCDEF89, true);
+Assert.assertEquals(dv.getUint32(0), 0x89EFCDAB);
+Assert.assertEquals(dv.getUint32(0, false), 0x89EFCDAB);
+Assert.assertEquals(dv.getUint32(0, true), 0xABCDEF89);
+
+// write explicit big endian, read big/little endian
+dv.setUint32(0, 0xABCDEF89, false);
+Assert.assertEquals(dv.getUint32(0), 0xABCDEF89);
+Assert.assertEquals(dv.getUint32(0, false), 0xABCDEF89);
+Assert.assertEquals(dv.getUint32(0, true), 0x89EFCDAB);
diff --git a/nashorn/test/script/basic/dataview_getset.js b/nashorn/test/script/basic/dataview_getset.js
new file mode 100644
index 00000000000..8c7a994c1d0
--- /dev/null
+++ b/nashorn/test/script/basic/dataview_getset.js
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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-8015958: DataView constructor is not defined
+ *
+ * @test
+ * @run
+ */
+
+// checking get/set of values of various types
+// Also basic endianess check.
+
+var Float = Java.type("java.lang.Float");
+var Double = Java.type("java.lang.Double");
+
+var DOUBLE_MIN = Double.MIN_VALUE;
+var DOUBLE_MIN_NORMAL = Double.MIN_NORMAL;
+var FLOAT_MIN = Float.MIN_VALUE;
+var FLOAT_MIN_NORMAL = Float.MIN_NORMAL;
+
+var buffer = new ArrayBuffer(12);
+var dv = new DataView(buffer);
+
+dv.setInt8(1, 123);
+Assert.assertEquals(dv.getInt8(1), 123);
+dv.setInt8(1, 123, true);
+Assert.assertEquals(dv.getInt8(1, true), 123);
+
+dv.setUint8(1, 255);
+Assert.assertEquals(dv.getUint8(1), 255);
+dv.setUint8(1, 255, true);
+Assert.assertEquals(dv.getUint8(1, true), 255);
+
+dv.setInt16(1, 1234);
+Assert.assertEquals(dv.getInt16(1), 1234);
+dv.setInt16(1, 1234, true);
+Assert.assertEquals(dv.getInt16(1, true), 1234);
+
+dv.setUint16(1, 65535);
+Assert.assertEquals(dv.getUint16(1), 65535);
+dv.setUint16(1, 65535, true);
+Assert.assertEquals(dv.getUint16(1, true), 65535);
+
+dv.setInt32(1, 1234);
+Assert.assertEquals(dv.getInt32(1), 1234);
+dv.setInt32(1, 1234, true);
+Assert.assertEquals(dv.getInt32(1, true), 1234);
+
+dv.setUint32(1, 4294967295);
+Assert.assertEquals(dv.getUint32(1), 4294967295);
+dv.setUint32(1, 4294967295, true);
+Assert.assertEquals(dv.getUint32(1, true), 4294967295);
+
+dv.setFloat64(1, Math.PI);
+Assert.assertEquals(dv.getFloat64(1), Math.PI, DOUBLE_MIN);
+dv.setFloat64(1, Math.PI, true);
+Assert.assertEquals(dv.getFloat64(1, true), Math.PI, DOUBLE_MIN);
+
+dv.setFloat64(1, DOUBLE_MIN_NORMAL);
+Assert.assertEquals(dv.getFloat64(1), DOUBLE_MIN_NORMAL, DOUBLE_MIN);
+dv.setFloat64(1, DOUBLE_MIN_NORMAL, true);
+Assert.assertEquals(dv.getFloat64(1, true), DOUBLE_MIN_NORMAL, DOUBLE_MIN);
+
+dv.setFloat32(1, 1.414);
+Assert["assertEquals(float, float, float)"](dv.getFloat32(1), 1.414, FLOAT_MIN);
+dv.setFloat32(1, 1.414, true);
+Assert["assertEquals(float, float, float)"](dv.getFloat32(1, true), 1.414, FLOAT_MIN);
+
+dv.setFloat32(1, FLOAT_MIN_NORMAL);
+Assert["assertEquals(float, float, float)"](dv.getFloat32(1), FLOAT_MIN_NORMAL, FLOAT_MIN);
+dv.setFloat32(1, FLOAT_MIN_NORMAL, true);
+Assert["assertEquals(float, float, float)"](dv.getFloat32(1, true), FLOAT_MIN_NORMAL, FLOAT_MIN);
diff --git a/nashorn/test/script/basic/dataview_new.js b/nashorn/test/script/basic/dataview_new.js
new file mode 100644
index 00000000000..78f8183d52a
--- /dev/null
+++ b/nashorn/test/script/basic/dataview_new.js
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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-8015958: DataView constructor is not defined
+ *
+ * @test
+ * @run
+ */
+
+// basic DataView constructor checks.
+
+// check ArrayBufferView property values of DataView instance
+function check(dv, buf, offset, length) {
+ if (dv.buffer !== buf) {
+ fail("DataView.buffer is wrong");
+ }
+
+ if (dv.byteOffset != offset) {
+ fail("DataView.byteOffset = " + dv.byteOffset + ", expected " + offset);
+ }
+
+ if (dv.byteLength != length) {
+ fail("DataView.byteLength = " + dv.byteLength + ", expected " + length);
+ }
+}
+
+var buffer = new ArrayBuffer(12);
+check(new DataView(buffer), buffer, 0, 12);
+check(new DataView(buffer, 2), buffer, 2, 10);
+check(new DataView(buffer, 4, 8), buffer, 4, 8);
+
+// make sure expected error is thrown
+function checkError(callback, ErrorType) {
+ try {
+ callback();
+ fail("Should have thrown " + ErrorType.name);
+ } catch (e) {
+ if (! (e instanceof ErrorType)) {
+ fail("Expected " + ErrorType.name + " got " + e);
+ }
+ }
+}
+
+// non ArrayBuffer as first arg
+checkError(function() { new DataView(344) }, TypeError);
+
+// illegal offset/length values
+checkError(function() { new DataView(buffer, -1) }, RangeError);
+checkError(function() { new DataView(buffer, 15) }, RangeError);
+checkError(function() { new DataView(buffer, 1, 32) }, RangeError);
From 29a22468e265db38cac053543a6195f18529be8d Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Thu, 13 Mar 2014 17:18:11 +0100
Subject: [PATCH 066/116] 8037238: JDK 9 images don't rebuild when access
bridge jars rebuild
Reviewed-by: tbell
---
make/common/JavaCompilation.gmk | 4 ++++
make/common/MakeBase.gmk | 5 +++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index 5ee8fdf301c..9cfed4a9a35 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -158,6 +158,10 @@ define SetupArchive
$1_DEPS+=$$(call CacheFind,$$(wildcard $$(addsuffix /META-INF,$$($1_SRCS))))
endif
endif
+ # The dependency list should never be empty
+ ifeq ($$(strip $$($1_DEPS)), )
+ $$(warning No dependencies found for $1)
+ endif
# Utility macros, to make the shell script receipt somewhat easier to decipher.
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 586d68ab937..869937431a2 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -436,7 +436,8 @@ not-containing = $(foreach v,$2,$(if $(findstring $1,$v),,$v))
# Param 1 - Dir to find in
ifeq ($(OPENJDK_BUILD_OS),windows)
define FillCacheFind
- FIND_CACHE_DIR += $1
+ # Remove any trailing slash from dirs in the cache dir list
+ FIND_CACHE_DIR += $$(patsubst %/,%, $1)
FIND_CACHE := $$(sort $$(FIND_CACHE) $$(shell $(FIND) $1 -type f -o -type l))
endef
else
@@ -451,7 +452,7 @@ endif
# The extra - is needed when FIND_CACHE_DIR is empty but should be harmless.
# Param 1 - Dirs to find in
define CacheFind
- $(if $(filter-out $(addsuffix %,- $(FIND_CACHE_DIR)),$1), \
+ $(if $(filter-out $(addsuffix /%,- $(FIND_CACHE_DIR)) $(FIND_CACHE_DIR),$1), \
$(shell $(FIND) $1 -type f -o -type l), \
$(filter $(addsuffix %,$1),$(FIND_CACHE)))
endef
From 73e0ab9b7fcab16802611685c5b16dd44edcd71b Mon Sep 17 00:00:00 2001
From: Vicente Romero
Date: Thu, 13 Mar 2014 17:36:51 +0000
Subject: [PATCH 067/116] 8034127: javac provide debug oriented toString()
methods to InferenceContext and UndetVar
Reviewed-by: jjg
---
.../com/sun/tools/javac/code/Type.java | 22 ++++++++++++++-----
.../com/sun/tools/javac/comp/Infer.java | 6 +++++
2 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
index da87eee67e0..0b57e21cbae 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -1481,8 +1481,21 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
}
public String toString() {
- if (inst != null) return inst.toString();
- else return qtype + "?";
+ return (inst == null) ? qtype + "?" : inst.toString();
+ }
+
+ public String debugString() {
+ String result = "inference var = " + qtype + "\n";
+ if (inst != null) {
+ result += "inst = " + inst + '\n';
+ }
+ for (InferenceBound bound: InferenceBound.values()) {
+ List aboundList = bounds.get(bound);
+ if (aboundList.size() > 0) {
+ result += bound + " = " + aboundList + '\n';
+ }
+ }
+ return result;
}
@Override
@@ -1492,8 +1505,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror {
@Override
public Type baseType() {
- if (inst != null) return inst.baseType();
- else return this;
+ return (inst == null) ? this : inst.baseType();
}
/** get all bounds of a given kind */
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
index 7fa54fc374c..1fe49587172 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
@@ -2173,6 +2173,12 @@ public class Infer {
//back-door to infer
return Infer.this;
}
+
+ @Override
+ public String toString() {
+ return "Inference vars: " + inferencevars + '\n' +
+ "Undet vars: " + undetvars;
+ }
}
final InferenceContext emptyContext = new InferenceContext(List.nil());
From 2564e82ad177c5c093d8033e33b3778439c779f6 Mon Sep 17 00:00:00 2001
From: Vicente Romero
Date: Thu, 13 Mar 2014 20:13:43 +0000
Subject: [PATCH 068/116] 8034924: Incorrect inheritance of inaccessible static
method
Reviewed-by: jjg, jlahoda
---
.../com/sun/tools/javac/code/Symbol.java | 36 +++++++---
.../IncorrectInheritanceTest.java | 68 +++++++++++++++++++
2 files changed, 93 insertions(+), 11 deletions(-)
create mode 100644 langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
index a5195caa8ee..1af2b332cc0 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -467,11 +467,24 @@ public abstract class Symbol extends AnnoConstruct implements Element {
private boolean hiddenIn(ClassSymbol clazz, Types types) {
Symbol sym = hiddenInInternal(clazz, types);
- return sym != null && sym != this;
+ Assert.check(sym != null, "the result of hiddenInInternal() can't be null");
+ /* If we find the current symbol then there is no symbol hiding it
+ */
+ return sym != this;
}
- private Symbol hiddenInInternal(ClassSymbol c, Types types) {
- Scope.Entry e = c.members().lookup(name);
+ /** This method looks in the supertypes graph that has the current class as the
+ * initial node, till it finds the current symbol or another symbol that hides it.
+ * If the current class has more than one supertype (extends one class and
+ * implements one or more interfaces) then null can be returned, meaning that
+ * a wrong path in the supertypes graph was selected. Null can only be returned
+ * as a temporary value, as a result of the recursive call.
+ */
+ private Symbol hiddenInInternal(ClassSymbol currentClass, Types types) {
+ if (currentClass == owner) {
+ return this;
+ }
+ Scope.Entry e = currentClass.members().lookup(name);
while (e.scope != null) {
if (e.sym.kind == kind &&
(kind != MTH ||
@@ -481,18 +494,19 @@ public abstract class Symbol extends AnnoConstruct implements Element {
}
e = e.next();
}
- List hiddenSyms = List.nil();
- for (Type st : types.interfaces(c.type).prepend(types.supertype(c.type))) {
+ Symbol hiddenSym = null;
+ for (Type st : types.interfaces(currentClass.type)
+ .prepend(types.supertype(currentClass.type))) {
if (st != null && (st.hasTag(CLASS))) {
Symbol sym = hiddenInInternal((ClassSymbol)st.tsym, types);
- if (sym != null) {
- hiddenSyms = hiddenSyms.prepend(hiddenInInternal((ClassSymbol)st.tsym, types));
+ if (sym == this) {
+ return this;
+ } else if (sym != null) {
+ hiddenSym = sym;
}
}
}
- return hiddenSyms.contains(this) ?
- this :
- (hiddenSyms.isEmpty() ? null : hiddenSyms.head);
+ return hiddenSym;
}
/** Is this symbol inherited into a given class?
diff --git a/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java b/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java
new file mode 100644
index 00000000000..a447d22fe15
--- /dev/null
+++ b/langtools/test/tools/javac/IncorrectInheritance/IncorrectInheritanceTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please 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 8034924
+ * @summary Incorrect inheritance of inaccessible static method
+ * @library /tools/javac/lib
+ * @build ToolBox
+ * @run main IncorrectInheritanceTest
+ */
+
+public class IncorrectInheritanceTest {
+ private static final String ASrc =
+ "package pkg;\n" +
+ "\n" +
+ "public class A {\n" +
+ " static void foo(Object o) {}\n" +
+ " private static void bar(Object o) {}\n" +
+ "}";
+
+ private static final String BSrc =
+ "import pkg.A;\n" +
+ "class B extends A {\n" +
+ " public void foo(Object o) {}\n" +
+ " public void bar(Object o) {}\n" +
+ "}";
+
+ private static final String CSrc =
+ "class C extends B {\n" +
+ " public void m(Object o) {\n" +
+ " foo(o);\n" +
+ " bar(o);\n" +
+ " }\n" +
+ "}";
+
+ public static void main(String[] args) throws Exception {
+ new IncorrectInheritanceTest().test();
+ }
+
+ public void test() throws Exception {
+ ToolBox.JavaToolArgs javacParams =
+ new ToolBox.JavaToolArgs()
+ .setSources(ASrc, BSrc, CSrc);
+ ToolBox.javac(javacParams);
+ }
+
+}
From 6151bfe1cb6faa8924731397adddadfdc9c54876 Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 14 Mar 2014 12:31:08 +0100
Subject: [PATCH 069/116] 8037281: Improve CacheFind and enable on all
platforms
Reviewed-by: tbell, ihse
---
make/common/JavaCompilation.gmk | 6 ++++++
make/common/MakeBase.gmk | 31 ++++++++++++++++++++++---------
2 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk
index 9cfed4a9a35..5b3f23741dd 100644
--- a/make/common/JavaCompilation.gmk
+++ b/make/common/JavaCompilation.gmk
@@ -143,6 +143,9 @@ define SetupArchive
ifneq (,$2)
$1_DEPS:=$2
else
+ # Add all source roots to the find cache since we are likely going to run find
+ # on these more than once. The cache will only be updated if necessary.
+ $$(eval $$(call FillCacheFind, $$($1_FIND_LIST)))
$1_DEPS:=$$(filter $$(addprefix %,$$($1_SUFFIXES)), \
$$(call CacheFind,$$($1_SRCS)))
ifneq (,$$($1_GREP_INCLUDE_PATTERNS))
@@ -424,6 +427,9 @@ define SetupJavaCompilation
# Make sure the dirs exist.
$$(foreach d,$$($1_SRC), $$(if $$(wildcard $$d),,$$(error SRC specified to SetupJavaCompilation $1 contains missing directory $$d)))
$$(eval $$(call MakeDir,$$($1_BIN)))
+ # Add all source roots to the find cache since we are likely going to run find
+ # on these more than once. The cache will only be updated if necessary.
+ $$(eval $$(call FillCacheFind,$$($1_SRC)))
# Find all files in the source trees.
$1_ALL_SRCS += $$(filter-out $(OVR_SRCS),$$(call CacheFind,$$($1_SRC)))
# Extract the java files.
diff --git a/make/common/MakeBase.gmk b/make/common/MakeBase.gmk
index 869937431a2..ca183ad3b86 100644
--- a/make/common/MakeBase.gmk
+++ b/make/common/MakeBase.gmk
@@ -420,6 +420,7 @@ endif
containing = $(foreach v,$2,$(if $(findstring $1,$v),$v))
not-containing = $(foreach v,$2,$(if $(findstring $1,$v),,$v))
+ifneq ($(DISABLE_CACHE_FIND), true)
################################################################################
# In Cygwin, finds are very costly, both because of expensive forks and because
# of bad file system caching. Find is used extensively in $(shell) commands to
@@ -433,17 +434,23 @@ not-containing = $(foreach v,$2,$(if $(findstring $1,$v),,$v))
#
# Needs to be called with $(eval )
#
+ # Even if the performance benifit is negligible on other platforms, keep the
+ # functionality active unless explicitly disabled to exercise it more.
+ #
+ # Initialize FIND_CACHE_DIRS with := to make it a non recursively-expanded variable
+ FIND_CACHE_DIRS :=
# Param 1 - Dir to find in
-ifeq ($(OPENJDK_BUILD_OS),windows)
define FillCacheFind
- # Remove any trailing slash from dirs in the cache dir list
- FIND_CACHE_DIR += $$(patsubst %/,%, $1)
- FIND_CACHE := $$(sort $$(FIND_CACHE) $$(shell $(FIND) $1 -type f -o -type l))
+ # Filter out already cached dirs. The - is needed when FIND_CACHE_DIR is empty
+ # since filter out will then return empty.
+ FIND_CACHE_NEW_DIRS := $$(filter-out $$(addsuffix /%,\
+ - $(FIND_CACHE_DIRS)) $(FIND_CACHE_DIRS), $1)
+ ifneq ($$(FIND_CACHE_NEW_DIRS), )
+ # Remove any trailing slash from dirs in the cache dir list
+ FIND_CACHE_DIRS += $$(patsubst %/,%, $$(FIND_CACHE_NEW_DIRS))
+ FIND_CACHE := $$(sort $$(FIND_CACHE) $$(shell $(FIND) $$(FIND_CACHE_NEW_DIRS) -type f -o -type l))
+ endif
endef
-else
- define FillCacheFind
- endef
-endif
# Mimics find by looking in the cache if all of the directories have been cached.
# Otherwise reverts to shell find. This is safe to call on all platforms, even if
@@ -452,10 +459,16 @@ endif
# The extra - is needed when FIND_CACHE_DIR is empty but should be harmless.
# Param 1 - Dirs to find in
define CacheFind
- $(if $(filter-out $(addsuffix /%,- $(FIND_CACHE_DIR)) $(FIND_CACHE_DIR),$1), \
+ $(if $(filter-out $(addsuffix /%,- $(FIND_CACHE_DIRS)) $(FIND_CACHE_DIRS),$1), \
$(shell $(FIND) $1 -type f -o -type l), \
$(filter $(addsuffix %,$1),$(FIND_CACHE)))
endef
+else
+ # If CacheFind is disabled, just run the find command.
+ define CacheFind
+ $(shell $(FIND) $1 -type f -o -type l)
+ endef
+endif
################################################################################
From ac1be38a4c434fb567a5c9798b4072094dfe354e Mon Sep 17 00:00:00 2001
From: Erik Joelsson
Date: Fri, 14 Mar 2014 13:16:46 +0100
Subject: [PATCH 070/116] 8010767: Build fails on OEL6 with 16 cores
Reviewed-by: tbell, ihse
---
common/autoconf/boot-jdk.m4 | 43 ++++--
common/autoconf/generated-configure.sh | 194 ++++++++++++++++---------
common/autoconf/spec.gmk.in | 8 +-
3 files changed, 165 insertions(+), 80 deletions(-)
diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4
index 170049731dc..edd6cec4ffb 100644
--- a/common/autoconf/boot-jdk.m4
+++ b/common/autoconf/boot-jdk.m4
@@ -350,8 +350,23 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
AC_MSG_CHECKING([flags for boot jdk java command] )
+ # Disable special log output when a debug build is used as Boot JDK...
+ ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA])
+
+ # Apply user provided options.
+ ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA])
+
+ AC_MSG_RESULT([$boot_jdk_jvmargs])
+
+ # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs
+ JAVA_FLAGS=$boot_jdk_jvmargs
+ AC_SUBST(JAVA_FLAGS)
+
+
+ AC_MSG_CHECKING([flags for boot jdk java command for big workloads])
+
# Starting amount of heap memory.
- ADD_JVM_ARG_IF_OK([-Xms64M],boot_jdk_jvmargs,[$JAVA])
+ ADD_JVM_ARG_IF_OK([-Xms64M],boot_jdk_jvmargs_big,[$JAVA])
# Maximum amount of heap memory.
# Maximum stack size.
@@ -366,20 +381,24 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
JVM_MAX_HEAP=1600M
STACK_SIZE=1536
fi
- ADD_JVM_ARG_IF_OK([-Xmx$JVM_MAX_HEAP],boot_jdk_jvmargs,[$JAVA])
- ADD_JVM_ARG_IF_OK([-XX:ThreadStackSize=$STACK_SIZE],boot_jdk_jvmargs,[$JAVA])
+ ADD_JVM_ARG_IF_OK([-Xmx$JVM_MAX_HEAP],boot_jdk_jvmargs_big,[$JAVA])
+ ADD_JVM_ARG_IF_OK([-XX:ThreadStackSize=$STACK_SIZE],boot_jdk_jvmargs_big,[$JAVA])
- # Disable special log output when a debug build is used as Boot JDK...
- ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA])
+ AC_MSG_RESULT([$boot_jdk_jvmargs_big])
- # Apply user provided options.
- ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA])
+ JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big
+ AC_SUBST(JAVA_FLAGS_BIG)
- AC_MSG_RESULT([$boot_jdk_jvmargs])
- # For now, general JAVA_FLAGS are the same as the boot jdk jvmargs
- JAVA_FLAGS=$boot_jdk_jvmargs
+ AC_MSG_CHECKING([flags for boot jdk java command for small workloads])
- AC_SUBST(BOOT_JDK_JVMARGS, $boot_jdk_jvmargs)
- AC_SUBST(JAVA_FLAGS, $JAVA_FLAGS)
+ # Use serial gc for small short lived tools if possible
+ ADD_JVM_ARG_IF_OK([-XX:+UseSerialGC],boot_jdk_jvmargs_small,[$JAVA])
+ ADD_JVM_ARG_IF_OK([-Xms32M],boot_jdk_jvmargs_small,[$JAVA])
+ ADD_JVM_ARG_IF_OK([-Xmx512M],boot_jdk_jvmargs_small,[$JAVA])
+
+ AC_MSG_RESULT([$boot_jdk_jvmargs_small])
+
+ JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small
+ AC_SUBST(JAVA_FLAGS_SMALL)
])
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 262655be633..b3d823b29ed 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -796,8 +796,9 @@ JAXWS_TOPDIR
JAXP_TOPDIR
CORBA_TOPDIR
LANGTOOLS_TOPDIR
+JAVA_FLAGS_SMALL
+JAVA_FLAGS_BIG
JAVA_FLAGS
-BOOT_JDK_JVMARGS
JAVAC_FLAGS
BOOT_JDK_SOURCETARGET
JARSIGNER
@@ -4231,7 +4232,7 @@ TOOLCHAIN_DESCRIPTION_xlc="IBM XL C/C++"
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1394150589
+DATE_WHEN_GENERATED=1394794899
###############################################################################
#
@@ -25866,67 +25867,6 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command " >&5
$as_echo_n "checking flags for boot jdk java command ... " >&6; }
- # Starting amount of heap memory.
-
- $ECHO "Check if jvm arg is ok: -Xms64M" >&5
- $ECHO "Command: $JAVA -Xms64M -version" >&5
- OUTPUT=`$JAVA -Xms64M -version 2>&1`
- FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
- FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
- if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
- boot_jdk_jvmargs="$boot_jdk_jvmargs -Xms64M"
- JVM_ARG_OK=true
- else
- $ECHO "Arg failed:" >&5
- $ECHO "$OUTPUT" >&5
- JVM_ARG_OK=false
- fi
-
-
- # Maximum amount of heap memory.
- # Maximum stack size.
- if test "x$BUILD_NUM_BITS" = x32; then
- JVM_MAX_HEAP=1100M
- STACK_SIZE=768
- else
- # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit
- # pointers are used. Apparently, we need to increase the heap and stack
- # space for the jvm. More specifically, when running javac to build huge
- # jdk batch
- JVM_MAX_HEAP=1600M
- STACK_SIZE=1536
- fi
-
- $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5
- $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5
- OUTPUT=`$JAVA -Xmx$JVM_MAX_HEAP -version 2>&1`
- FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
- FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
- if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
- boot_jdk_jvmargs="$boot_jdk_jvmargs -Xmx$JVM_MAX_HEAP"
- JVM_ARG_OK=true
- else
- $ECHO "Arg failed:" >&5
- $ECHO "$OUTPUT" >&5
- JVM_ARG_OK=false
- fi
-
-
- $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5
- $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5
- OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1`
- FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
- FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
- if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
- boot_jdk_jvmargs="$boot_jdk_jvmargs -XX:ThreadStackSize=$STACK_SIZE"
- JVM_ARG_OK=true
- else
- $ECHO "Arg failed:" >&5
- $ECHO "$OUTPUT" >&5
- JVM_ARG_OK=false
- fi
-
-
# Disable special log output when a debug build is used as Boot JDK...
$ECHO "Check if jvm arg is ok: -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" >&5
@@ -25967,9 +25907,133 @@ $as_echo "$boot_jdk_jvmargs" >&6; }
# For now, general JAVA_FLAGS are the same as the boot jdk jvmargs
JAVA_FLAGS=$boot_jdk_jvmargs
- BOOT_JDK_JVMARGS=$boot_jdk_jvmargs
- JAVA_FLAGS=$JAVA_FLAGS
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for big workloads" >&5
+$as_echo_n "checking flags for boot jdk java command for big workloads... " >&6; }
+
+ # Starting amount of heap memory.
+
+ $ECHO "Check if jvm arg is ok: -Xms64M" >&5
+ $ECHO "Command: $JAVA -Xms64M -version" >&5
+ OUTPUT=`$JAVA -Xms64M -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xms64M"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ # Maximum amount of heap memory.
+ # Maximum stack size.
+ if test "x$BUILD_NUM_BITS" = x32; then
+ JVM_MAX_HEAP=1100M
+ STACK_SIZE=768
+ else
+ # Running Javac on a JVM on a 64-bit machine, takes more space since 64-bit
+ # pointers are used. Apparently, we need to increase the heap and stack
+ # space for the jvm. More specifically, when running javac to build huge
+ # jdk batch
+ JVM_MAX_HEAP=1600M
+ STACK_SIZE=1536
+ fi
+
+ $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5
+ $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5
+ OUTPUT=`$JAVA -Xmx$JVM_MAX_HEAP -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -Xmx$JVM_MAX_HEAP"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ $ECHO "Check if jvm arg is ok: -XX:ThreadStackSize=$STACK_SIZE" >&5
+ $ECHO "Command: $JAVA -XX:ThreadStackSize=$STACK_SIZE -version" >&5
+ OUTPUT=`$JAVA -XX:ThreadStackSize=$STACK_SIZE -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_big="$boot_jdk_jvmargs_big -XX:ThreadStackSize=$STACK_SIZE"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_big" >&5
+$as_echo "$boot_jdk_jvmargs_big" >&6; }
+
+ JAVA_FLAGS_BIG=$boot_jdk_jvmargs_big
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command for small workloads" >&5
+$as_echo_n "checking flags for boot jdk java command for small workloads... " >&6; }
+
+ # Use serial gc for small short lived tools if possible
+
+ $ECHO "Check if jvm arg is ok: -XX:+UseSerialGC" >&5
+ $ECHO "Command: $JAVA -XX:+UseSerialGC -version" >&5
+ OUTPUT=`$JAVA -XX:+UseSerialGC -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:+UseSerialGC"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ $ECHO "Check if jvm arg is ok: -Xms32M" >&5
+ $ECHO "Command: $JAVA -Xms32M -version" >&5
+ OUTPUT=`$JAVA -Xms32M -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xms32M"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ $ECHO "Check if jvm arg is ok: -Xmx512M" >&5
+ $ECHO "Command: $JAVA -Xmx512M -version" >&5
+ OUTPUT=`$JAVA -Xmx512M -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -Xmx512M"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5
+$as_echo "$boot_jdk_jvmargs_small" >&6; }
+
+ JAVA_FLAGS_SMALL=$boot_jdk_jvmargs_small
diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in
index 46874b09633..fe5fb1be8d8 100644
--- a/common/autoconf/spec.gmk.in
+++ b/common/autoconf/spec.gmk.in
@@ -254,7 +254,6 @@ BUILD_HOTSPOT=@BUILD_HOTSPOT@
# The boot jdk to use
BOOT_JDK:=@BOOT_JDK@
-BOOT_JDK_JVMARGS:=@BOOT_JDK_JVMARGS@
BOOT_RTJAR:=@BOOT_RTJAR@
BOOT_TOOLSJAR=$(BOOT_JDK)/lib/tools.jar
@@ -442,8 +441,11 @@ POST_STRIP_CMD:=@POST_STRIP_CMD@
POST_MCS_CMD:=@POST_MCS_CMD@
JAVA_FLAGS:=@JAVA_FLAGS@
+JAVA_FLAGS_BIG:=@JAVA_FLAGS_BIG@
+JAVA_FLAGS_SMALL:=@JAVA_FLAGS_SMALL@
-JAVA=@FIXPATH@ @JAVA@ $(JAVA_FLAGS)
+JAVA=@FIXPATH@ @JAVA@ $(JAVA_FLAGS_BIG) $(JAVA_FLAGS)
+JAVA_SMALL=@FIXPATH@ @JAVA@ $(JAVA_FLAGS_SMALL) $(JAVA_FLAGS)
JAVAC:=@FIXPATH@ @JAVAC@
# Hotspot sets this variable before reading the SPEC when compiling sa-jdi.jar. Avoid
@@ -454,7 +456,7 @@ JAVAH:=@FIXPATH@ @JAVAH@
JAR:=@FIXPATH@ @JAR@
-NATIVE2ASCII:=@FIXPATH@ @NATIVE2ASCII@
+NATIVE2ASCII:=@FIXPATH@ @NATIVE2ASCII@ $(addprefix -J, $(JAVA_FLAGS_SMALL))
JARSIGNER:=@FIXPATH@ @JARSIGNER@
From 53e3990b7cc0d50b201d2d34b0d1b090fabc81ab Mon Sep 17 00:00:00 2001
From: Eric McCorkle
Date: Fri, 14 Mar 2014 15:35:13 -0400
Subject: [PATCH 071/116] 8037420: Silent failures in
Annotate.actualEnterTypeAnnotations
Remove two silent failures
Reviewed-by: jjg
---
.../classes/com/sun/tools/javac/comp/Annotate.java | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
index cd1383b3b0a..1a9e0626b1c 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
@@ -808,9 +808,7 @@ public class Annotate {
Attribute.TypeCompound tc =
enterTypeAnnotation(a, syms.annotationType, env);
- if (tc == null) {
- continue;
- }
+ Assert.checkNonNull(tc, "Failed to create type annotation");
if (annotated.containsKey(a.type.tsym)) {
if (!allowRepeatedAnnos) {
@@ -827,10 +825,9 @@ public class Annotate {
}
}
- if (s != null) {
- s.appendTypeAttributesWithCompletion(
- new AnnotateRepeatedContext<>(env, annotated, pos, log, true));
- }
+ Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is null");
+ s.appendTypeAttributesWithCompletion(
+ new AnnotateRepeatedContext<>(env, annotated, pos, log, true));
} finally {
if (prevLintPos != null)
deferredLintHandler.setPos(prevLintPos);
From e34f74421a2b3e4a571f6d89f7b996fcf4e4ad30 Mon Sep 17 00:00:00 2001
From: Athijegannathan Sundararajan
Date: Mon, 17 Mar 2014 18:02:00 +0530
Subject: [PATCH 072/116] 8037400: Remove getInitialMap getters and
GlobalObject interface
Reviewed-by: lagergren, jlaskey, attila
---
nashorn/make/build.xml | 2 +
.../api/scripting/NashornScriptEngine.java | 67 +++--
.../api/scripting/ScriptObjectMirror.java | 22 +-
.../objects/AccessorPropertyDescriptor.java | 6 +-
.../internal/objects/ArrayBufferView.java | 6 +-
.../objects/DataPropertyDescriptor.java | 6 +-
.../objects/GenericPropertyDescriptor.java | 6 +-
.../jdk/nashorn/internal/objects/Global.java | 170 ++++++++++---
.../nashorn/internal/objects/NativeArray.java | 6 +-
.../internal/objects/NativeArrayBuffer.java | 6 +-
.../internal/objects/NativeBoolean.java | 6 +-
.../nashorn/internal/objects/NativeDate.java | 6 +-
.../nashorn/internal/objects/NativeError.java | 6 +-
.../internal/objects/NativeEvalError.java | 6 +-
.../internal/objects/NativeJSAdapter.java | 6 +-
.../internal/objects/NativeJavaImporter.java | 6 +-
.../internal/objects/NativeNumber.java | 6 +-
.../internal/objects/NativeRangeError.java | 6 +-
.../objects/NativeReferenceError.java | 6 +-
.../internal/objects/NativeRegExp.java | 6 +-
.../objects/NativeRegExpExecResult.java | 6 +-
.../internal/objects/NativeString.java | 6 +-
.../internal/objects/NativeSyntaxError.java | 6 +-
.../internal/objects/NativeTypeError.java | 6 +-
.../internal/objects/NativeURIError.java | 6 +-
.../internal/objects/PrototypeObject.java | 4 -
.../internal/objects/ScriptFunctionImpl.java | 36 +--
.../jdk/nashorn/internal/runtime/Context.java | 78 +++---
.../internal/runtime/DebuggerSupport.java | 4 +-
.../nashorn/internal/runtime/ECMAErrors.java | 57 ++---
.../internal/runtime/GlobalObject.java | 228 ------------------
.../internal/runtime/JSONFunctions.java | 21 +-
.../jdk/nashorn/internal/runtime/JSType.java | 9 +-
.../nashorn/internal/runtime/ListAdapter.java | 13 +-
.../internal/runtime/NativeJavaPackage.java | 3 +-
.../internal/runtime/ParserException.java | 3 +-
.../internal/runtime/ScriptFunction.java | 5 +-
.../internal/runtime/ScriptFunctionData.java | 5 +-
.../internal/runtime/ScriptObject.java | 20 +-
.../internal/runtime/ScriptRuntime.java | 2 +-
.../internal/runtime/SetMethodCreator.java | 2 +-
.../runtime/UserAccessorProperty.java | 5 +-
.../internal/runtime/arrays/ArrayData.java | 4 +-
.../runtime/arrays/ByteBufferArrayData.java | 5 +-
.../runtime/arrays/FrozenArrayFilter.java | 4 +-
.../runtime/arrays/SealedArrayFilter.java | 4 +-
.../linker/JavaAdapterBytecodeGenerator.java | 22 +-
.../runtime/linker/JavaAdapterFactory.java | 6 +-
.../linker/NashornPrimitiveLinker.java | 4 +-
nashorn/src/jdk/nashorn/tools/Shell.java | 19 +-
.../internal/codegen/CompilerTest.java | 5 +-
.../performance/PerformanceWrapper.java | 4 +-
.../nashorn/internal/runtime/ContextTest.java | 5 +-
.../framework/SharedContextEvaluator.java | 6 +-
54 files changed, 376 insertions(+), 594 deletions(-)
delete mode 100644 nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml
index a33e355ce91..74eae86a588 100644
--- a/nashorn/make/build.xml
+++ b/nashorn/make/build.xml
@@ -125,6 +125,7 @@
+
@@ -243,6 +244,7 @@
+
diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index 3c4d29fc025..9c14359ec4e 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -57,9 +57,9 @@ import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager;
-import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -99,7 +99,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private final boolean _global_per_engine;
// This is the initial default Nashorn global object.
// This is used as "shared" global if above option is true.
- private final ScriptObject global;
+ private final Global global;
// initialized bit late to be made 'final'.
// Property object for "context" property of global object.
private volatile Property contextProperty;
@@ -264,7 +264,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
public Object __noSuchProperty__(final Object self, final ScriptContext ctxt, final String name) {
if (ctxt != null) {
final int scope = ctxt.getAttributesScope(name);
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(ctxt);
+ final Global ctxtGlobal = getNashornGlobalFrom(ctxt);
if (scope != -1) {
return ScriptObjectMirror.unwrap(ctxt.getAttribute(name, scope), ctxtGlobal);
}
@@ -317,7 +317,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
ScriptObject realSelf = null;
- ScriptObject realGlobal = null;
+ Global realGlobal = null;
if(thiz == null) {
// making interface out of global functions
realSelf = realGlobal = getNashornGlobalFrom(context);
@@ -346,7 +346,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
try {
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != realGlobal);
try {
if (globalChanged) {
@@ -371,7 +371,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
// Retrieve nashorn Global object for a given ScriptContext object
- private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) {
+ private Global getNashornGlobalFrom(final ScriptContext ctxt) {
if (_global_per_engine) {
// shared single global object for all ENGINE_SCOPE Bindings
return global;
@@ -380,18 +380,18 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE);
// is this Nashorn's own Bindings implementation?
if (bindings instanceof ScriptObjectMirror) {
- final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings);
- if (sobj != null) {
- return sobj;
+ final Global glob = globalFromMirror((ScriptObjectMirror)bindings);
+ if (glob != null) {
+ return glob;
}
}
// Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it!
Object scope = bindings.get(NASHORN_GLOBAL);
if (scope instanceof ScriptObjectMirror) {
- final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope);
- if (sobj != null) {
- return sobj;
+ final Global glob = globalFromMirror((ScriptObjectMirror)scope);
+ if (glob != null) {
+ return glob;
}
}
@@ -399,14 +399,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
// Create new global instance mirror and associate with the Bindings.
final ScriptObjectMirror mirror = createGlobalMirror(ctxt);
bindings.put(NASHORN_GLOBAL, mirror);
- return mirror.getScriptObject();
+ return mirror.getHomeGlobal();
}
// Retrieve nashorn Global object from a given ScriptObjectMirror
- private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) {
+ private Global globalFromMirror(final ScriptObjectMirror mirror) {
ScriptObject sobj = mirror.getScriptObject();
- if (sobj instanceof GlobalObject && isOfContext(sobj, nashornContext)) {
- return sobj;
+ if (sobj instanceof Global && isOfContext((Global)sobj, nashornContext)) {
+ return (Global)sobj;
}
return null;
@@ -414,15 +414,15 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
// Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object
private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) {
- final ScriptObject newGlobal = createNashornGlobal(ctxt);
+ final Global newGlobal = createNashornGlobal(ctxt);
return new ScriptObjectMirror(newGlobal, newGlobal);
}
// Create a new Nashorn Global object
- private ScriptObject createNashornGlobal(final ScriptContext ctxt) {
- final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction() {
+ private Global createNashornGlobal(final ScriptContext ctxt) {
+ final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction() {
@Override
- public ScriptObject run() {
+ public Global run() {
try {
return nashornContext.newGlobal();
} catch (final RuntimeException e) {
@@ -460,7 +460,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
// scripts should see "context" and "engine" as variables in the given global object
- private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) {
+ private void setContextVariables(final Global ctxtGlobal, final ScriptContext ctxt) {
// set "context" global variable via contextProperty - because this
// property is non-writable
contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
@@ -470,7 +470,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
// if no arguments passed, expose it
if (! (args instanceof ScriptObject)) {
- args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
+ args = ctxtGlobal.wrapAsObject(args);
ctxtGlobal.set("arguments", args, false);
}
}
@@ -478,7 +478,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException {
name.getClass(); // null check
- ScriptObject invokeGlobal = null;
+ Global invokeGlobal = null;
ScriptObjectMirror selfMirror = null;
if (selfObject instanceof ScriptObjectMirror) {
selfMirror = (ScriptObjectMirror)selfObject;
@@ -489,7 +489,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
} else if (selfObject instanceof ScriptObject) {
// invokeMethod called from script code - in which case we may get 'naked' ScriptObject
// Wrap it with oldGlobal to make a ScriptObjectMirror for the same.
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
invokeGlobal = oldGlobal;
if (oldGlobal == null) {
throw new IllegalArgumentException(getMessage("no.current.nashorn.global"));
@@ -502,7 +502,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(selfObject, oldGlobal);
} else if (selfObject == null) {
// selfObject is null => global function call
- final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
+ final Global ctxtGlobal = getNashornGlobalFrom(context);
invokeGlobal = ctxtGlobal;
selfMirror = (ScriptObjectMirror)ScriptObjectMirror.wrap(ctxtGlobal, ctxtGlobal);
}
@@ -532,11 +532,11 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
}
- private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException {
+ private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
if (script == null) {
return null;
}
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != ctxtGlobal);
try {
if (globalChanged) {
@@ -558,7 +558,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
}
}
- private static void throwAsScriptException(final Exception e, final ScriptObject global) throws ScriptException {
+ private static void throwAsScriptException(final Exception e, final Global global) throws ScriptException {
if (e instanceof ScriptException) {
throw (ScriptException)e;
} else if (e instanceof NashornException) {
@@ -582,7 +582,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return new CompiledScript() {
@Override
public Object eval(final ScriptContext ctxt) throws ScriptException {
- final ScriptObject globalObject = getNashornGlobalFrom(ctxt);
+ final Global globalObject = getNashornGlobalFrom(ctxt);
// Are we running the script in the correct global?
if (func.getScope() == globalObject) {
return evalImpl(func, ctxt, globalObject);
@@ -602,8 +602,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return compileImpl(source, getNashornGlobalFrom(ctxt));
}
- private ScriptFunction compileImpl(final Source source, final ScriptObject newGlobal) throws ScriptException {
- final ScriptObject oldGlobal = Context.getGlobal();
+ private ScriptFunction compileImpl(final Source source, final Global newGlobal) throws ScriptException {
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != newGlobal);
try {
if (globalChanged) {
@@ -641,8 +641,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C
return true;
}
- private static boolean isOfContext(final ScriptObject global, final Context context) {
- assert global instanceof GlobalObject: "Not a Global object";
- return ((GlobalObject)global).isOfContext(context);
+ private static boolean isOfContext(final Global global, final Context context) {
+ return global.isOfContext(context);
}
}
diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
index 7a9792df19c..b12553369d4 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
@@ -42,10 +42,10 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.script.Bindings;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
-import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -64,7 +64,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt();
private final ScriptObject sobj;
- private final ScriptObject global;
+ private final Global global;
private final boolean strict;
@Override
@@ -95,7 +95,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
@Override
public Object call(final Object thiz, final Object... args) {
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
try {
@@ -125,7 +125,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
@Override
public Object newObject(final Object... args) {
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
try {
@@ -171,7 +171,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
public Object callMember(final String functionName, final Object... args) {
functionName.getClass(); // null check
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
try {
@@ -642,7 +642,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
*/
public static Object wrap(final Object obj, final Object homeGlobal) {
if(obj instanceof ScriptObject) {
- return homeGlobal instanceof ScriptObject ? new ScriptObjectMirror((ScriptObject)obj, (ScriptObject)homeGlobal) : obj;
+ return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
}
if(obj instanceof ConsString) {
return obj.toString();
@@ -710,13 +710,13 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
// package-privates below this.
- ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
+ ScriptObjectMirror(final ScriptObject sobj, final Global global) {
assert sobj != null : "ScriptObjectMirror on null!";
- assert global instanceof GlobalObject : "global is not a GlobalObject";
+ assert global != null : "home Global is null";
this.sobj = sobj;
this.global = global;
- this.strict = ((GlobalObject)global).isStrictContext();
+ this.strict = global.isStrictContext();
}
// accessors for script engine
@@ -724,7 +724,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
return sobj;
}
- ScriptObject getHomeGlobal() {
+ Global getHomeGlobal() {
return global;
}
@@ -734,7 +734,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
// internals only below this.
private V inGlobal(final Callable callable) {
- final ScriptObject oldGlobal = Context.getGlobal();
+ final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != global);
if (globalChanged) {
Context.setGlobal(global);
diff --git a/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
index b3388eb0813..e39c521724c 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/AccessorPropertyDescriptor.java
@@ -67,12 +67,8 @@ public final class AccessorPropertyDescriptor extends ScriptObject implements Pr
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
AccessorPropertyDescriptor(final boolean configurable, final boolean enumerable, final Object get, final Object set, final Global global) {
- super(global.getObjectPrototype(), getInitialMap());
+ super(global.getObjectPrototype(), $nasgenmap$);
this.configurable = configurable;
this.enumerable = enumerable;
this.get = get;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
index a7252fcc606..7bd1d2f91dd 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
@@ -42,12 +42,8 @@ abstract class ArrayBufferView extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength, final Global global) {
- super(getInitialMap());
+ super($nasgenmap$);
checkConstructorArgs(buffer, byteOffset, elementLength);
this.setProto(getPrototype(global));
this.setArray(factory().createArrayData(buffer, byteOffset, elementLength));
diff --git a/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
index 9f7d2e4f8e8..e117c7ed2f2 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/DataPropertyDescriptor.java
@@ -64,12 +64,8 @@ public final class DataPropertyDescriptor extends ScriptObject implements Proper
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
DataPropertyDescriptor(final boolean configurable, final boolean enumerable, final boolean writable, final Object value, final Global global) {
- super(global.getObjectPrototype(), getInitialMap());
+ super(global.getObjectPrototype(), $nasgenmap$);
this.configurable = configurable;
this.enumerable = enumerable;
this.writable = writable;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java b/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
index bfa06cb3b35..19cc8b6fd29 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/GenericPropertyDescriptor.java
@@ -55,12 +55,8 @@ public final class GenericPropertyDescriptor extends ScriptObject implements Pro
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
GenericPropertyDescriptor(final boolean configurable, final boolean enumerable, final Global global) {
- super(global.getObjectPrototype(), getInitialMap());
+ super(global.getObjectPrototype(), $nasgenmap$);
this.configurable = configurable;
this.enumerable = enumerable;
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java
index 0d8ac5caf6a..9e40dbeb1c2 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java
@@ -48,7 +48,6 @@ import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.GlobalFunctions;
-import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.NativeJavaPackage;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
@@ -70,7 +69,7 @@ import jdk.nashorn.internal.scripts.JO;
* Representation of global scope.
*/
@ScriptClass("Global")
-public final class Global extends ScriptObject implements GlobalObject, Scope {
+public final class Global extends ScriptObject implements Scope {
private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
@@ -433,11 +432,9 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
* @return the global singleton
*/
public static Global instance() {
- ScriptObject global = Context.getGlobal();
- if (! (global instanceof Global)) {
- throw new IllegalStateException("no current global instance");
- }
- return (Global)global;
+ Global global = Context.getGlobal();
+ global.getClass(); // null check
+ return global;
}
/**
@@ -458,19 +455,30 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return instance().getContext();
}
- // GlobalObject interface implementation
+ // Runtime interface to Global
- @Override
+ /**
+ * Is this global of the given Context?
+ * @param ctxt the context
+ * @return true if this global belongs to the given Context
+ */
public boolean isOfContext(final Context ctxt) {
return this.context == ctxt;
}
- @Override
+ /**
+ * Does this global belong to a strict Context?
+ * @return true if this global belongs to a strict Context
+ */
public boolean isStrictContext() {
return context.getEnv()._strict;
}
- @Override
+ /**
+ * Initialize standard builtin objects like "Object", "Array", "Function" etc.
+ * as well as our extension builtin objects like "Java", "JSAdapter" as properties
+ * of the global scope object.
+ */
public void initBuiltinObjects() {
if (this.builtinObject != null) {
// already initialized, just return
@@ -480,12 +488,26 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
init();
}
- @Override
+ /**
+ * Create a new ScriptFunction object
+ *
+ * @param name function name
+ * @param handle invocation handle for function
+ * @param scope the scope
+ * @param strict are we in strict mode
+ *
+ * @return new script function
+ */
public ScriptFunction newScriptFunction(final String name, final MethodHandle handle, final ScriptObject scope, final boolean strict) {
return new ScriptFunctionImpl(name, handle, scope, null, strict ? ScriptFunctionData.IS_STRICT_CONSTRUCTOR : ScriptFunctionData.IS_CONSTRUCTOR);
}
- @Override
+ /**
+ * Wrap a Java object as corresponding script object
+ *
+ * @param obj object to wrap
+ * @return wrapped object
+ */
public Object wrapAsObject(final Object obj) {
if (obj instanceof Boolean) {
return new NativeBoolean((Boolean)obj, this);
@@ -507,7 +529,14 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
}
}
- @Override
+ /**
+ * Lookup helper for JS primitive types
+ *
+ * @param request the link request for the dynamic call site.
+ * @param self self reference
+ *
+ * @return guarded invocation
+ */
public GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
if (self instanceof String || self instanceof ConsString) {
return NativeString.lookupPrimitive(request, self);
@@ -519,12 +548,23 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
throw new IllegalArgumentException("Unsupported primitive: " + self);
}
- @Override
+ /**
+ * Create a new empty script object
+ *
+ * @return the new ScriptObject
+ */
public ScriptObject newObject() {
return new JO(getObjectPrototype(), JO.getInitialMap());
}
- @Override
+ /**
+ * Default value of given type
+ *
+ * @param sobj script object
+ * @param typeHint type hint
+ *
+ * @return default value
+ */
public Object getDefaultValue(final ScriptObject sobj, final Class> typeHint) {
// When the [[DefaultValue]] internal method of O is called with no hint,
// then it behaves as if the hint were Number, unless O is a Date object
@@ -584,7 +624,12 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return UNDEFINED;
}
- @Override
+ /**
+ * Is the given ScriptObject an ECMAScript Error object?
+ *
+ * @param sobj the object being checked
+ * @return true if sobj is an Error object
+ */
public boolean isError(final ScriptObject sobj) {
final ScriptObject errorProto = getErrorPrototype();
ScriptObject proto = sobj.getProto();
@@ -597,52 +642,108 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
return false;
}
- @Override
+ /**
+ * Create a new ECMAScript Error object.
+ *
+ * @param msg error message
+ * @return newly created Error object
+ */
public ScriptObject newError(final String msg) {
return new NativeError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript EvalError object.
+ *
+ * @param msg error message
+ * @return newly created EvalError object
+ */
public ScriptObject newEvalError(final String msg) {
return new NativeEvalError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript RangeError object.
+ *
+ * @param msg error message
+ * @return newly created RangeError object
+ */
public ScriptObject newRangeError(final String msg) {
return new NativeRangeError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript ReferenceError object.
+ *
+ * @param msg error message
+ * @return newly created ReferenceError object
+ */
public ScriptObject newReferenceError(final String msg) {
return new NativeReferenceError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript SyntaxError object.
+ *
+ * @param msg error message
+ * @return newly created SyntaxError object
+ */
public ScriptObject newSyntaxError(final String msg) {
return new NativeSyntaxError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript TypeError object.
+ *
+ * @param msg error message
+ * @return newly created TypeError object
+ */
public ScriptObject newTypeError(final String msg) {
return new NativeTypeError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript URIError object.
+ *
+ * @param msg error message
+ * @return newly created URIError object
+ */
public ScriptObject newURIError(final String msg) {
return new NativeURIError(msg, this);
}
- @Override
+ /**
+ * Create a new ECMAScript GenericDescriptor object.
+ *
+ * @param configurable is the property configurable?
+ * @param enumerable is the property enumerable?
+ * @return newly created GenericDescriptor object
+ */
public PropertyDescriptor newGenericDescriptor(final boolean configurable, final boolean enumerable) {
return new GenericPropertyDescriptor(configurable, enumerable, this);
}
- @Override
+ /**
+ * Create a new ECMAScript DatePropertyDescriptor object.
+ *
+ * @param value of the data property
+ * @param configurable is the property configurable?
+ * @param enumerable is the property enumerable?
+ * @return newly created DataPropertyDescriptor object
+ */
public PropertyDescriptor newDataDescriptor(final Object value, final boolean configurable, final boolean enumerable, final boolean writable) {
return new DataPropertyDescriptor(configurable, enumerable, writable, value, this);
}
- @Override
+ /**
+ * Create a new ECMAScript AccessorPropertyDescriptor object.
+ *
+ * @param get getter function of the user accessor property
+ * @param set setter function of the user accessor property
+ * @param configurable is the property configurable?
+ * @param enumerable is the property enumerable?
+ * @return newly created AccessorPropertyDescriptor object
+ */
public PropertyDescriptor newAccessorDescriptor(final Object get, final Object set, final boolean configurable, final boolean enumerable) {
final AccessorPropertyDescriptor desc = new AccessorPropertyDescriptor(configurable, enumerable, get == null ? UNDEFINED : get, set == null ? UNDEFINED : set, this);
@@ -675,14 +776,25 @@ public final class Global extends ScriptObject implements GlobalObject, Scope {
private final Map namedInvokers = new ConcurrentHashMap<>();
- @Override
+
+ /**
+ * Get cached InvokeByName object for the given key
+ * @param key key to be associated with InvokeByName object
+ * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
+ * @return InvokeByName object associated with the key.
+ */
public InvokeByName getInvokeByName(final Object key, final Callable creator) {
return getLazilyCreatedValue(key, creator, namedInvokers);
}
private final Map dynamicInvokers = new ConcurrentHashMap<>();
- @Override
+ /**
+ * Get cached dynamic method handle for the given key
+ * @param key key to be associated with dynamic method handle
+ * @param creator if method handle is absent 'creator' is called to make one (lazy init)
+ * @return dynamic method handle associated with the key.
+ */
public MethodHandle getDynamicInvoker(final Object key, final Callable creator) {
return getLazilyCreatedValue(key, creator, dynamicInvokers);
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
index cc62d23cc1f..168a2f8a9ec 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -156,10 +156,6 @@ public final class NativeArray extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
/*
* Constructors.
*/
@@ -208,7 +204,7 @@ public final class NativeArray extends ScriptObject {
}
NativeArray(final ArrayData arrayData, final Global global) {
- super(global.getArrayPrototype(), getInitialMap());
+ super(global.getArrayPrototype(), $nasgenmap$);
this.setArray(arrayData);
this.setIsArray();
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
index 49082498b57..49a61c96df3 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java
@@ -44,10 +44,6 @@ final class NativeArrayBuffer extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
if (args.length == 0) {
@@ -58,7 +54,7 @@ final class NativeArrayBuffer extends ScriptObject {
}
protected NativeArrayBuffer(final byte[] byteArray, final Global global) {
- super(global.getArrayBufferPrototype(), getInitialMap());
+ super(global.getArrayBufferPrototype(), $nasgenmap$);
this.buffer = byteArray;
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
index bde6c608519..f737a6c898b 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeBoolean.java
@@ -59,17 +59,13 @@ public final class NativeBoolean extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeBoolean(final boolean value, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
this.value = value;
}
NativeBoolean(final boolean flag, final Global global) {
- this(flag, global.getBooleanPrototype(), getInitialMap());
+ this(flag, global.getBooleanPrototype(), $nasgenmap$);
}
NativeBoolean(final boolean flag) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java
index b0d120222a9..34e27f173ac 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java
@@ -114,10 +114,6 @@ public final class NativeDate extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeDate(final double time, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
final ScriptEnvironment env = Global.getEnv();
@@ -127,7 +123,7 @@ public final class NativeDate extends ScriptObject {
}
NativeDate(final double time, final Global global) {
- this(time, global.getDatePrototype(), getInitialMap());
+ this(time, global.getDatePrototype(), $nasgenmap$);
}
private NativeDate (final double time) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
index e1a4730d553..3dea27288b0 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
@@ -92,10 +92,6 @@ public final class NativeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
private NativeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
@@ -108,7 +104,7 @@ public final class NativeError extends ScriptObject {
}
NativeError(final Object msg, final Global global) {
- this(msg, global.getErrorPrototype(), getInitialMap());
+ this(msg, global.getErrorPrototype(), $nasgenmap$);
}
private NativeError(final Object msg) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java
index bb11ef6c354..2b343ede673 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeEvalError.java
@@ -62,10 +62,6 @@ public final class NativeEvalError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
private NativeEvalError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
@@ -78,7 +74,7 @@ public final class NativeEvalError extends ScriptObject {
}
NativeEvalError(final Object msg, final Global global) {
- this(msg, global.getEvalErrorPrototype(), getInitialMap());
+ this(msg, global.getEvalErrorPrototype(), $nasgenmap$);
}
private NativeEvalError(final Object msg) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index ed879dc69b5..b71b4276cd8 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -146,10 +146,6 @@ public final class NativeJSAdapter extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
NativeJSAdapter(final Object overrides, final ScriptObject adaptee, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
this.adaptee = wrapAdaptee(adaptee);
@@ -577,7 +573,7 @@ public final class NativeJSAdapter extends ScriptObject {
proto = global.getJSAdapterPrototype();
}
- return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, getInitialMap());
+ return new NativeJSAdapter(overrides, (ScriptObject)adaptee, (ScriptObject)proto, $nasgenmap$);
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
index c86f3053526..49be8a7c473 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
@@ -60,17 +60,13 @@ public final class NativeJavaImporter extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeJavaImporter(final Object[] args, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
this.args = args;
}
private NativeJavaImporter(final Object[] args, final Global global) {
- this(args, global.getJavaImporterPrototype(), getInitialMap());
+ this(args, global.getJavaImporterPrototype(), $nasgenmap$);
}
private NativeJavaImporter(final Object[] args) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
index 02d9b99efdc..4181d205051 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
@@ -90,10 +90,6 @@ public final class NativeNumber extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeNumber(final double value, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
this.value = value;
@@ -102,7 +98,7 @@ public final class NativeNumber extends ScriptObject {
}
NativeNumber(final double value, final Global global) {
- this(value, global.getNumberPrototype(), getInitialMap());
+ this(value, global.getNumberPrototype(), $nasgenmap$);
}
private NativeNumber(final double value) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java
index 6e0d954bc7c..4b2bebcfd2d 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRangeError.java
@@ -62,10 +62,6 @@ public final class NativeRangeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
private NativeRangeError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
@@ -78,7 +74,7 @@ public final class NativeRangeError extends ScriptObject {
}
NativeRangeError(final Object msg, final Global global) {
- this(msg, global.getRangeErrorPrototype(), getInitialMap());
+ this(msg, global.getRangeErrorPrototype(), $nasgenmap$);
}
private NativeRangeError(final Object msg) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java
index 052950c6d24..504f16ecd6c 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeReferenceError.java
@@ -62,10 +62,6 @@ public final class NativeReferenceError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
private NativeReferenceError(final Object msg, final ScriptObject proto, final PropertyMap map) {
super(proto, map);
@@ -78,7 +74,7 @@ public final class NativeReferenceError extends ScriptObject {
}
NativeReferenceError(final Object msg, final Global global) {
- this(msg, global.getReferenceErrorPrototype(), getInitialMap());
+ this(msg, global.getReferenceErrorPrototype(), $nasgenmap$);
}
private NativeReferenceError(final Object msg) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
index abc3366d353..04b828bfc21 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -70,12 +70,8 @@ public final class NativeRegExp extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeRegExp(final Global global) {
- super(global.getRegExpPrototype(), getInitialMap());
+ super(global.getRegExpPrototype(), $nasgenmap$);
this.globalObject = global;
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
index 5d79699e2ae..f12cea12c13 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
@@ -53,12 +53,8 @@ public final class NativeRegExpExecResult extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
NativeRegExpExecResult(final RegExpResult result, final Global global) {
- super(global.getArrayPrototype(), getInitialMap());
+ super(global.getArrayPrototype(), $nasgenmap$);
setIsArray();
this.setArray(ArrayData.allocate(result.getGroups().clone()));
this.index = result.getIndex();
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
index 53ae9a23004..c75b2b00362 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java
@@ -78,16 +78,12 @@ public final class NativeString extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
private NativeString(final CharSequence value) {
this(value, Global.instance());
}
NativeString(final CharSequence value, final Global global) {
- this(value, global.getStringPrototype(), getInitialMap());
+ this(value, global.getStringPrototype(), $nasgenmap$);
}
private NativeString(final CharSequence value, final ScriptObject proto, final PropertyMap map) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
index ffe1b0a7432..6515f3cc2e6 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeSyntaxError.java
@@ -62,13 +62,9 @@ public final class NativeSyntaxError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
NativeSyntaxError(final Object msg, final Global global) {
- super(global.getSyntaxErrorPrototype(), getInitialMap());
+ super(global.getSyntaxErrorPrototype(), $nasgenmap$);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java
index 067139cda3d..f799b1767d0 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeTypeError.java
@@ -62,13 +62,9 @@ public final class NativeTypeError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
NativeTypeError(final Object msg, final Global global) {
- super(global.getTypeErrorPrototype(), getInitialMap());
+ super(global.getTypeErrorPrototype(), $nasgenmap$);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java
index 382e23f4b65..fd59bc8a209 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeURIError.java
@@ -61,13 +61,9 @@ public final class NativeURIError extends ScriptObject {
// initialized by nasgen
private static PropertyMap $nasgenmap$;
- static PropertyMap getInitialMap() {
- return $nasgenmap$;
- }
-
@SuppressWarnings("LeakingThisInConstructor")
NativeURIError(final Object msg, final Global global) {
- super(global.getURIErrorPrototype(), getInitialMap());
+ super(global.getURIErrorPrototype(), $nasgenmap$);
if (msg != UNDEFINED) {
this.instMessage = JSType.toString(msg);
} else {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java b/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java
index 1fd4f60d5a0..483f6174702 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java
@@ -57,10 +57,6 @@ public class PrototypeObject extends ScriptObject {
map$ = PropertyMap.newMap(properties);
}
- static PropertyMap getInitialMap() {
- return map$;
- }
-
private PrototypeObject(final Global global, final PropertyMap map) {
super(global.getObjectPrototype(), map != map$? map.addAll(map$) : map$);
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
index fe18be990b3..dcbc7da99c8 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@@ -55,27 +55,11 @@ public class ScriptFunctionImpl extends ScriptFunction {
// property map for non-strict, non-bound functions.
private static final PropertyMap map$;
- static PropertyMap getInitialMap() {
- return map$;
- }
-
- static PropertyMap getInitialAnonymousMap() {
- return AnonymousFunction.getInitialMap();
- }
-
- static PropertyMap getInitialStrictMap() {
- return strictmodemap$;
- }
-
- static PropertyMap getInitialBoundMap() {
- return boundfunctionmap$;
- }
-
// Marker object for lazily initialized prototype object
private static final Object LAZY_PROTOTYPE = new Object();
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
- super(name, invokeHandle, getInitialMap(), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
+ super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -92,7 +76,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
- super(name, invokeHandle, map.addAll(getInitialMap()), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
+ super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -110,7 +94,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
- super(name, methodHandle, getMap(global, isStrict(flags)), scope, specs, flags);
+ super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags);
init(global);
}
@@ -128,7 +112,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) {
- super(data, getMap(global, data.isStrict()), scope);
+ super(data, getMap(data.isStrict()), scope);
init(global);
}
@@ -148,7 +132,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param global the global object
*/
ScriptFunctionImpl(final ScriptFunctionData data, final Global global) {
- super(data, getInitialBoundMap(), null);
+ super(data, boundfunctionmap$, null);
init(global);
}
@@ -176,8 +160,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
}
// Choose the map based on strict mode!
- private static PropertyMap getMap(final Global global, final boolean strict) {
- return strict ? getInitialStrictMap() : getInitialMap();
+ private static PropertyMap getMap(final boolean strict) {
+ return strict ? strictmodemap$ : map$;
}
private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
@@ -191,12 +175,8 @@ public class ScriptFunctionImpl extends ScriptFunction {
private static class AnonymousFunction extends ScriptFunctionImpl {
private static final PropertyMap anonmap$ = PropertyMap.newMap();
- static PropertyMap getInitialMap() {
- return anonmap$;
- }
-
AnonymousFunction(final Global global) {
- super("", GlobalFunctions.ANONYMOUS, getInitialAnonymousMap(), null);
+ super("", GlobalFunctions.ANONYMOUS, anonmap$, null);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
index aaf9bbdd35d..f3ec08757d1 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
@@ -156,7 +156,7 @@ public final class Context {
/** Is Context global debug mode enabled ? */
public static final boolean DEBUG = Options.getBooleanProperty("nashorn.debug");
- private static final ThreadLocal currentGlobal = new ThreadLocal<>();
+ private static final ThreadLocal currentGlobal = new ThreadLocal<>();
// class cache
private ClassCache classCache;
@@ -165,10 +165,10 @@ public final class Context {
* Get the current global scope
* @return the current global scope
*/
- public static ScriptObject getGlobal() {
+ public static Global getGlobal() {
// This class in a package.access protected package.
// Trusted code only can call this method.
- return getGlobalTrusted();
+ return currentGlobal.get();
}
/**
@@ -177,10 +177,19 @@ public final class Context {
*/
public static void setGlobal(final ScriptObject global) {
if (global != null && !(global instanceof Global)) {
- throw new IllegalArgumentException("global is not an instance of Global!");
+ throw new IllegalArgumentException("not a global!");
}
+ setGlobal((Global)global);
+ }
- setGlobalTrusted(global);
+ /**
+ * Set the current global scope
+ * @param global the global scope
+ */
+ public static void setGlobal(final Global global) {
+ // This class in a package.access protected package.
+ // Trusted code only can call this method.
+ currentGlobal.set(global);
}
/**
@@ -201,7 +210,7 @@ public final class Context {
* @return error writer of the current context
*/
public static PrintWriter getCurrentErr() {
- final ScriptObject global = getGlobalTrusted();
+ final ScriptObject global = getGlobal();
return (global != null)? global.getContext().getErr() : new PrintWriter(System.err);
}
@@ -406,7 +415,7 @@ public final class Context {
* @return the property map of the current global scope
*/
public static PropertyMap getGlobalMap() {
- return Context.getGlobalTrusted().getMap();
+ return Context.getGlobal().getMap();
}
/**
@@ -436,7 +445,7 @@ public final class Context {
final String file = (location == UNDEFINED || location == null) ? "" : location.toString();
final Source source = new Source(file, string);
final boolean directEval = location != UNDEFINED; // is this direct 'eval' call or indirectly invoked eval?
- final ScriptObject global = Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
ScriptObject scope = initialScope;
@@ -468,7 +477,7 @@ public final class Context {
// in the caller's environment. A new environment is created!
if (strictFlag) {
// Create a new scope object
- final ScriptObject strictEvalScope = ((GlobalObject)global).newObject();
+ final ScriptObject strictEvalScope = global.newObject();
// bless it as a "scope"
strictEvalScope.setIsScope();
@@ -593,10 +602,10 @@ public final class Context {
* @throws IOException if source cannot be found or loaded
*/
public Object loadWithNewGlobal(final Object from, final Object...args) throws IOException {
- final ScriptObject oldGlobal = getGlobalTrusted();
- final ScriptObject newGlobal = AccessController.doPrivileged(new PrivilegedAction() {
+ final Global oldGlobal = getGlobal();
+ final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction() {
@Override
- public ScriptObject run() {
+ public Global run() {
try {
return newGlobal();
} catch (final RuntimeException e) {
@@ -609,17 +618,17 @@ public final class Context {
}, CREATE_GLOBAL_ACC_CTXT);
// initialize newly created Global instance
initGlobal(newGlobal);
- setGlobalTrusted(newGlobal);
+ setGlobal(newGlobal);
final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal);
- newGlobal.put("arguments", ((GlobalObject)newGlobal).wrapAsObject(wrapped), env._strict);
+ newGlobal.put("arguments", newGlobal.wrapAsObject(wrapped), env._strict);
try {
// wrap objects from newGlobal's world as mirrors - but if result
// is from oldGlobal's world, unwrap it!
return ScriptObjectMirror.unwrap(ScriptObjectMirror.wrap(load(newGlobal, from), newGlobal), oldGlobal);
} finally {
- setGlobalTrusted(oldGlobal);
+ setGlobal(oldGlobal);
}
}
@@ -794,7 +803,7 @@ public final class Context {
*
* @return the initialized global scope object.
*/
- public ScriptObject createGlobal() {
+ public Global createGlobal() {
return initGlobal(newGlobal());
}
@@ -802,7 +811,7 @@ public final class Context {
* Create a new uninitialized global scope object
* @return the global script object
*/
- public ScriptObject newGlobal() {
+ public Global newGlobal() {
return new Global(this);
}
@@ -812,20 +821,16 @@ public final class Context {
* @param global the global
* @return the initialized global scope object.
*/
- public ScriptObject initGlobal(final ScriptObject global) {
- if (! (global instanceof GlobalObject)) {
- throw new IllegalArgumentException("not a global object!");
- }
-
+ public Global initGlobal(final Global global) {
// Need only minimal global object, if we are just compiling.
if (!env._compile_only) {
- final ScriptObject oldGlobal = Context.getGlobalTrusted();
+ final Global oldGlobal = Context.getGlobal();
try {
- Context.setGlobalTrusted(global);
+ Context.setGlobal(global);
// initialize global scope with builtin global objects
- ((GlobalObject)global).initBuiltinObjects();
+ global.initBuiltinObjects();
} finally {
- Context.setGlobalTrusted(oldGlobal);
+ Context.setGlobal(oldGlobal);
}
}
@@ -833,30 +838,15 @@ public final class Context {
}
/**
- * Trusted variants - package-private
+ * Trusted variant - package-private
*/
- /**
- * Return the current global scope
- * @return current global scope
- */
- static ScriptObject getGlobalTrusted() {
- return currentGlobal.get();
- }
-
- /**
- * Set the current global scope
- */
- static void setGlobalTrusted(ScriptObject global) {
- currentGlobal.set(global);
- }
-
/**
* Return the current global's context
* @return current global's context
*/
static Context getContextTrusted() {
- return Context.getGlobalTrusted().getContext();
+ return ((ScriptObject)Context.getGlobal()).getContext();
}
/**
@@ -925,7 +915,7 @@ public final class Context {
}
// Package as a JavaScript function and pass function back to shell.
- return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
+ return Context.getGlobal().newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
}
private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java
index c288a963321..261bc0200aa 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java
@@ -75,7 +75,7 @@ final class DebuggerSupport {
* @return context global.
*/
static Object getGlobal() {
- return Context.getGlobalTrusted();
+ return Context.getGlobal();
}
/**
@@ -87,7 +87,7 @@ final class DebuggerSupport {
* @return Result of eval as string, or, an exception or null depending on returnException.
*/
static Object eval(final ScriptObject scope, final Object self, final String string, final boolean returnException) {
- final ScriptObject global = Context.getGlobalTrusted();
+ final ScriptObject global = Context.getGlobal();
final ScriptObject initialScope = scope != null ? scope : global;
final Object callThis = self != null ? self : global;
final Context context = global.getContext();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java
index 754ebbf955f..affba497b18 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java
@@ -31,6 +31,7 @@ import java.util.ResourceBundle;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.scripts.JS;
import jdk.nashorn.internal.codegen.CompilerConstants;
+import jdk.nashorn.internal.objects.Global;
/**
* Helper class to throw various standard "ECMA error" exceptions such as Error, ReferenceError, TypeError etc.
@@ -66,7 +67,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException asEcmaException(final ParserException e) {
- return asEcmaException(Context.getGlobalTrusted(), e);
+ return asEcmaException(Context.getGlobal(), e);
}
/**
@@ -78,11 +79,11 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException asEcmaException(final ScriptObject global, final ParserException e) {
+ public static ECMAException asEcmaException(final Global global, final ParserException e) {
final JSErrorType errorType = e.getErrorType();
assert errorType != null : "error type for " + e + " was null";
- final GlobalObject globalObj = (GlobalObject)global;
+ final Global globalObj = global;
final String msg = e.getMessage();
// translate to ECMAScript Error object using error type
@@ -116,7 +117,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException syntaxError(final String msgId, final String... args) {
- return syntaxError(Context.getGlobalTrusted(), msgId, args);
+ return syntaxError(Context.getGlobal(), msgId, args);
}
/**
@@ -128,7 +129,7 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException syntaxError(final ScriptObject global, final String msgId, final String... args) {
+ public static ECMAException syntaxError(final Global global, final String msgId, final String... args) {
return syntaxError(global, null, msgId, args);
}
@@ -142,7 +143,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException syntaxError(final Throwable cause, final String msgId, final String... args) {
- return syntaxError(Context.getGlobalTrusted(), cause, msgId, args);
+ return syntaxError(Context.getGlobal(), cause, msgId, args);
}
/**
@@ -155,9 +156,9 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException syntaxError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
+ public static ECMAException syntaxError(final Global global, final Throwable cause, final String msgId, final String... args) {
final String msg = getMessage("syntax.error." + msgId, args);
- return error(((GlobalObject)global).newSyntaxError(msg), cause);
+ return error(global.newSyntaxError(msg), cause);
}
/**
@@ -169,7 +170,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException typeError(final String msgId, final String... args) {
- return typeError(Context.getGlobalTrusted(), msgId, args);
+ return typeError(Context.getGlobal(), msgId, args);
}
/**
@@ -181,7 +182,7 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException typeError(final ScriptObject global, final String msgId, final String... args) {
+ public static ECMAException typeError(final Global global, final String msgId, final String... args) {
return typeError(global, null, msgId, args);
}
@@ -195,7 +196,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException typeError(final Throwable cause, final String msgId, final String... args) {
- return typeError(Context.getGlobalTrusted(), cause, msgId, args);
+ return typeError(Context.getGlobal(), cause, msgId, args);
}
/**
@@ -208,9 +209,9 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException typeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
+ public static ECMAException typeError(final Global global, final Throwable cause, final String msgId, final String... args) {
final String msg = getMessage("type.error." + msgId, args);
- return error(((GlobalObject)global).newTypeError(msg), cause);
+ return error(global.newTypeError(msg), cause);
}
/**
@@ -222,7 +223,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException rangeError(final String msgId, final String... args) {
- return rangeError(Context.getGlobalTrusted(), msgId, args);
+ return rangeError(Context.getGlobal(), msgId, args);
}
/**
@@ -234,7 +235,7 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException rangeError(final ScriptObject global, final String msgId, final String... args) {
+ public static ECMAException rangeError(final Global global, final String msgId, final String... args) {
return rangeError(global, null, msgId, args);
}
@@ -248,7 +249,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException rangeError(final Throwable cause, final String msgId, final String... args) {
- return rangeError(Context.getGlobalTrusted(), cause, msgId, args);
+ return rangeError(Context.getGlobal(), cause, msgId, args);
}
/**
@@ -261,9 +262,9 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException rangeError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
+ public static ECMAException rangeError(final Global global, final Throwable cause, final String msgId, final String... args) {
final String msg = getMessage("range.error." + msgId, args);
- return error(((GlobalObject)global).newRangeError(msg), cause);
+ return error(global.newRangeError(msg), cause);
}
/**
@@ -275,7 +276,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException referenceError(final String msgId, final String... args) {
- return referenceError(Context.getGlobalTrusted(), msgId, args);
+ return referenceError(Context.getGlobal(), msgId, args);
}
/**
@@ -287,7 +288,7 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException referenceError(final ScriptObject global, final String msgId, final String... args) {
+ public static ECMAException referenceError(final Global global, final String msgId, final String... args) {
return referenceError(global, null, msgId, args);
}
@@ -301,7 +302,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException referenceError(final Throwable cause, final String msgId, final String... args) {
- return referenceError(Context.getGlobalTrusted(), cause, msgId, args);
+ return referenceError(Context.getGlobal(), cause, msgId, args);
}
/**
@@ -314,9 +315,9 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException referenceError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
+ public static ECMAException referenceError(final Global global, final Throwable cause, final String msgId, final String... args) {
final String msg = getMessage("reference.error." + msgId, args);
- return error(((GlobalObject)global).newReferenceError(msg), cause);
+ return error(global.newReferenceError(msg), cause);
}
/**
@@ -328,7 +329,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException uriError(final String msgId, final String... args) {
- return uriError(Context.getGlobalTrusted(), msgId, args);
+ return uriError(Context.getGlobal(), msgId, args);
}
/**
@@ -340,7 +341,7 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException uriError(final ScriptObject global, final String msgId, final String... args) {
+ public static ECMAException uriError(final Global global, final String msgId, final String... args) {
return uriError(global, null, msgId, args);
}
@@ -354,7 +355,7 @@ public final class ECMAErrors {
* @return the resulting {@link ECMAException}
*/
public static ECMAException uriError(final Throwable cause, final String msgId, final String... args) {
- return uriError(Context.getGlobalTrusted(), cause, msgId, args);
+ return uriError(Context.getGlobal(), cause, msgId, args);
}
/**
@@ -367,9 +368,9 @@ public final class ECMAErrors {
*
* @return the resulting {@link ECMAException}
*/
- public static ECMAException uriError(final ScriptObject global, final Throwable cause, final String msgId, final String... args) {
+ public static ECMAException uriError(final Global global, final Throwable cause, final String msgId, final String... args) {
final String msg = getMessage("uri.error." + msgId, args);
- return error(((GlobalObject)global).newURIError(msg), cause);
+ return error(global.newURIError(msg), cause);
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
deleted file mode 100644
index 20046388292..00000000000
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java
+++ /dev/null
@@ -1,228 +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;
-
-import java.lang.invoke.MethodHandle;
-import java.util.concurrent.Callable;
-import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.LinkRequest;
-import jdk.nashorn.internal.runtime.linker.InvokeByName;
-
-/**
- * Runtime interface to the global scope objects.
- */
-
-public interface GlobalObject {
- /**
- * Is this global of the given Context?
- * @param ctxt the context
- * @return true if this global belongs to the given Context
- */
- public boolean isOfContext(final Context ctxt);
-
- /**
- * Does this global belong to a strict Context?
- * @return true if this global belongs to a strict Context
- */
- public boolean isStrictContext();
-
- /**
- * Initialize standard builtin objects like "Object", "Array", "Function" etc.
- * as well as our extension builtin objects like "Java", "JSAdapter" as properties
- * of the global scope object.
- */
- public void initBuiltinObjects();
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newScriptFunction(String, MethodHandle, ScriptObject, boolean)}
- *
- * @param name function name
- * @param handle invocation handle for function
- * @param scope the scope
- * @param strict are we in strict mode
- *
- * @return new script function
- */
- public ScriptFunction newScriptFunction(String name, MethodHandle handle, ScriptObject scope, boolean strict);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#wrapAsObject(Object)}
- *
- * @param obj object to wrap
- * @return wrapped object
- */
- public Object wrapAsObject(Object obj);
-
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#primitiveLookup(LinkRequest, Object)}
- *
- * @param request the link request for the dynamic call site.
- * @param self self reference
- *
- * @return guarded invocation
- */
- public GuardedInvocation primitiveLookup(LinkRequest request, Object self);
-
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newObject()}
- *
- * @return the new ScriptObject
- */
- public ScriptObject newObject();
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#isError(ScriptObject)}
- *
- * @param sobj to check if it is an error object
- * @return true if error object
- */
- public boolean isError(ScriptObject sobj);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the error
- */
- public ScriptObject newError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newEvalError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the eval error
- */
- public ScriptObject newEvalError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newRangeError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the range error
- */
- public ScriptObject newRangeError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newReferenceError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the reference error
- */
- public ScriptObject newReferenceError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newSyntaxError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the syntax error
- */
- public ScriptObject newSyntaxError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newTypeError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the type error
- */
- public ScriptObject newTypeError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newURIError(String)}
- *
- * @param msg the error message
- *
- * @return the new ScriptObject representing the URI error
- */
- public ScriptObject newURIError(String msg);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newGenericDescriptor(boolean, boolean)}
- *
- * @param configurable is the described property configurable
- * @param enumerable is the described property enumerable
- *
- * @return property descriptor
- */
- public PropertyDescriptor newGenericDescriptor(boolean configurable, boolean enumerable);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newDataDescriptor(Object, boolean, boolean, boolean)}
- *
- * @param value data value
- * @param configurable is the described property configurable
- * @param enumerable is the described property enumerable
- * @param writable is the described property writable
- *
- * @return property descriptor
- */
- public PropertyDescriptor newDataDescriptor(Object value, boolean configurable, boolean enumerable, boolean writable);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#newAccessorDescriptor(Object, Object, boolean, boolean)}
- *
- * @param get property getter, or null if none
- * @param set property setter, or null if none
- * @param configurable is the described property configurable
- * @param enumerable is the described property enumerable
- *
- * @return property descriptor
- */
- public PropertyDescriptor newAccessorDescriptor(Object get, Object set, boolean configurable, boolean enumerable);
-
- /**
- * Wrapper for {@link jdk.nashorn.internal.objects.Global#getDefaultValue(ScriptObject, Class)}
- *
- * @param sobj script object
- * @param typeHint type hint
- *
- * @return default value
- */
- public Object getDefaultValue(ScriptObject sobj, Class> typeHint);
-
- /**
- * Get cached InvokeByName object for the given key
- * @param key key to be associated with InvokeByName object
- * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init)
- * @return InvokeByName object associated with the key.
- */
- public InvokeByName getInvokeByName(final Object key, final Callable creator);
-
- /**
- * Get cached dynamic method handle for the given key
- * @param key key to be associated with dynamic method handle
- * @param creator if method handle is absent 'creator' is called to make one (lazy init)
- * @return dynamic method handle associated with the key.
- */
- public MethodHandle getDynamicInvoker(final Object key, final Callable creator);
-}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
index 73552cb10df..64863184759 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
@@ -33,6 +33,7 @@ import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.UnaryNode;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.JSONParser;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
@@ -47,7 +48,7 @@ public final class JSONFunctions {
private static final Object REVIVER_INVOKER = new Object();
private static MethodHandle getREVIVER_INVOKER() {
- return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(REVIVER_INVOKER,
+ return Context.getGlobal().getDynamicInvoker(REVIVER_INVOKER,
new Callable() {
@Override
public MethodHandle call() {
@@ -88,7 +89,7 @@ public final class JSONFunctions {
throw ECMAErrors.syntaxError(e, "invalid.json", e.getMessage());
}
- final ScriptObject global = Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
Object unfiltered = convertNode(global, node);
return applyReviver(global, unfiltered, reviver);
}
@@ -98,10 +99,10 @@ public final class JSONFunctions {
// parse helpers
// apply 'reviver' function if available
- private static Object applyReviver(final ScriptObject global, final Object unfiltered, final Object reviver) {
+ private static Object applyReviver(final Global global, final Object unfiltered, final Object reviver) {
if (reviver instanceof ScriptFunction) {
- assert global instanceof GlobalObject;
- final ScriptObject root = ((GlobalObject)global).newObject();
+ assert global instanceof Global;
+ final ScriptObject root = global.newObject();
root.addOwnProperty("", Property.WRITABLE_ENUMERABLE_CONFIGURABLE, unfiltered);
return walk(root, "", (ScriptFunction)reviver);
}
@@ -138,8 +139,8 @@ public final class JSONFunctions {
}
// Converts IR node to runtime value
- private static Object convertNode(final ScriptObject global, final Node node) {
- assert global instanceof GlobalObject;
+ private static Object convertNode(final Global global, final Node node) {
+ assert global instanceof Global;
if (node instanceof LiteralNode) {
// check for array literal
@@ -157,7 +158,7 @@ public final class JSONFunctions {
for (final Node elem : elements) {
values[index++] = JSType.toNumber(convertNode(global, elem));
}
- return ((GlobalObject)global).wrapAsObject(values);
+ return global.wrapAsObject(values);
}
final Object[] values = new Object[elements.length];
@@ -167,14 +168,14 @@ public final class JSONFunctions {
values[index++] = convertNode(global, elem);
}
- return ((GlobalObject)global).wrapAsObject(values);
+ return global.wrapAsObject(values);
}
return ((LiteralNode>)node).getValue();
} else if (node instanceof ObjectNode) {
final ObjectNode objNode = (ObjectNode) node;
- final ScriptObject object = ((GlobalObject)global).newObject();
+ final ScriptObject object = global.newObject();
for (final PropertyNode pNode: objNode.getElements()) {
final Node valueNode = pNode.getValue();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
index 541301960c9..c49de9cf4e6 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
@@ -36,6 +36,7 @@ import java.util.List;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -852,7 +853,7 @@ public enum JSType {
* @return the wrapped object
*/
public static Object toScriptObject(final Object obj) {
- return toScriptObject(Context.getGlobalTrusted(), obj);
+ return toScriptObject(Context.getGlobal(), obj);
}
/**
@@ -865,7 +866,7 @@ public enum JSType {
*
* @return the wrapped object
*/
- public static Object toScriptObject(final ScriptObject global, final Object obj) {
+ public static Object toScriptObject(final Global global, final Object obj) {
if (nullOrUndefined(obj)) {
throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
}
@@ -874,7 +875,7 @@ public enum JSType {
return obj;
}
- return ((GlobalObject)global).wrapAsObject(obj);
+ return global.wrapAsObject(obj);
}
/**
@@ -984,7 +985,7 @@ public enum JSType {
if (obj instanceof ScriptObject) {
if (safe) {
final ScriptObject sobj = (ScriptObject)obj;
- final GlobalObject gobj = (GlobalObject)Context.getGlobalTrusted();
+ final Global gobj = Context.getGlobal();
return gobj.isError(sobj) ?
ECMAException.safeToString(sobj) :
sobj.safeToString();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java
index 26c22c390b9..9a3408fbbd6 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java
@@ -34,6 +34,7 @@ import java.util.RandomAccess;
import java.util.concurrent.Callable;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -54,7 +55,7 @@ public abstract class ListAdapter extends AbstractList implements Random
// These add to the back and front of the list
private static final Object PUSH = new Object();
private static InvokeByName getPUSH() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH,
+ return Context.getGlobal().getInvokeByName(PUSH,
new Callable() {
@Override
public InvokeByName call() {
@@ -65,7 +66,7 @@ public abstract class ListAdapter extends AbstractList implements Random
private static final Object UNSHIFT = new Object();
private static InvokeByName getUNSHIFT() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(UNSHIFT,
+ return Context.getGlobal().getInvokeByName(UNSHIFT,
new Callable() {
@Override
public InvokeByName call() {
@@ -77,7 +78,7 @@ public abstract class ListAdapter extends AbstractList implements Random
// These remove from the back and front of the list
private static final Object POP = new Object();
private static InvokeByName getPOP() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP,
+ return Context.getGlobal().getInvokeByName(POP,
new Callable() {
@Override
public InvokeByName call() {
@@ -88,7 +89,7 @@ public abstract class ListAdapter extends AbstractList implements Random
private static final Object SHIFT = new Object();
private static InvokeByName getSHIFT() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(SHIFT,
+ return Context.getGlobal().getInvokeByName(SHIFT,
new Callable() {
@Override
public InvokeByName call() {
@@ -100,7 +101,7 @@ public abstract class ListAdapter extends AbstractList implements Random
// These insert and remove in the middle of the list
private static final Object SPLICE_ADD = new Object();
private static InvokeByName getSPLICE_ADD() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD,
+ return Context.getGlobal().getInvokeByName(SPLICE_ADD,
new Callable() {
@Override
public InvokeByName call() {
@@ -111,7 +112,7 @@ public abstract class ListAdapter extends AbstractList implements Random
private static final Object SPLICE_REMOVE = new Object();
private static InvokeByName getSPLICE_REMOVE() {
- return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_REMOVE,
+ return Context.getGlobal().getInvokeByName(SPLICE_REMOVE,
new Callable() {
@Override
public InvokeByName call() {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
index 591fd327c64..fbca1c340bd 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
@@ -35,7 +35,6 @@ import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
-import jdk.nashorn.internal.objects.NativeJava;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -52,7 +51,7 @@ import jdk.nashorn.internal.objects.annotations.Function;
* var ArrayList = java.util.ArrayList
* var list = new ArrayList
*
- * You can also use {@link NativeJava#type(Object, Object)} to access Java classes. These two statements are mostly
+ * You can also use {@link jdk.nashorn.internal.objects.NativeJava#type(Object, Object)} to access Java classes. These two statements are mostly
* equivalent:
*
* var listType1 = java.util.ArrayList
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
index 2424bc3f1be..5137d596ee7 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import jdk.nashorn.api.scripting.NashornException;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.Token;
/**
@@ -110,7 +111,7 @@ public final class ParserException extends NashornException {
* Throw this {@code ParserException} as one of the 7 native JavaScript errors
* @param global global scope object
*/
- public void throwAsEcmaException(final ScriptObject global) {
+ public void throwAsEcmaException(final Global global) {
throw ECMAErrors.asEcmaException(global, this);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index d0c6989b14a..3d8b4ff288b 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -38,6 +38,7 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
@@ -475,14 +476,14 @@ public abstract class ScriptFunction extends ScriptObject {
if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
return obj;
}
- return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(obj);
+ return Context.getGlobal().wrapAsObject(obj);
}
@SuppressWarnings("unused")
private static Object globalFilter(final Object object) {
// replace whatever we get with the current global object
- return Context.getGlobalTrusted();
+ return Context.getGlobal();
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index de39449b81b..aee367d65ba 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -32,6 +32,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
/**
@@ -372,11 +373,11 @@ public abstract class ScriptFunctionData {
private Object convertThisObject(final Object thiz) {
if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
if (JSType.nullOrUndefined(thiz)) {
- return Context.getGlobalTrusted();
+ return Context.getGlobal();
}
if (isPrimitiveThis(thiz)) {
- return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
+ return Context.getGlobal().wrapAsObject(thiz);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 4696bdeacad..05e236e3bd6 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -325,18 +325,18 @@ public abstract class ScriptObject implements PropertyAccess {
* @return property descriptor
*/
public final PropertyDescriptor toPropertyDescriptor() {
- final GlobalObject global = (GlobalObject) Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
final PropertyDescriptor desc;
if (isDataDescriptor()) {
if (has(SET) || has(GET)) {
- throw typeError((ScriptObject)global, "inconsistent.property.descriptor");
+ throw typeError(global, "inconsistent.property.descriptor");
}
desc = global.newDataDescriptor(UNDEFINED, false, false, false);
} else if (isAccessorDescriptor()) {
if (has(VALUE) || has(WRITABLE)) {
- throw typeError((ScriptObject)global, "inconsistent.property.descriptor");
+ throw typeError(global, "inconsistent.property.descriptor");
}
desc = global.newAccessorDescriptor(UNDEFINED, UNDEFINED, false, false);
@@ -355,7 +355,7 @@ public abstract class ScriptObject implements PropertyAccess {
*
* @return property descriptor
*/
- public static PropertyDescriptor toPropertyDescriptor(final ScriptObject global, final Object obj) {
+ public static PropertyDescriptor toPropertyDescriptor(final Global global, final Object obj) {
if (obj instanceof ScriptObject) {
return ((ScriptObject)obj).toPropertyDescriptor();
}
@@ -374,7 +374,7 @@ public abstract class ScriptObject implements PropertyAccess {
public Object getOwnPropertyDescriptor(final String key) {
final Property property = getMap().findProperty(key);
- final GlobalObject global = (GlobalObject)Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
if (property != null) {
final ScriptFunction get = property.getGetterFunction(this);
@@ -439,7 +439,7 @@ public abstract class ScriptObject implements PropertyAccess {
* @return true if property was successfully defined
*/
public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
- final ScriptObject global = Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
final PropertyDescriptor desc = toPropertyDescriptor(global, propertyDesc);
final Object current = getOwnPropertyDescriptor(key);
final String name = JSType.toString(key);
@@ -637,7 +637,7 @@ public abstract class ScriptObject implements PropertyAccess {
final int propFlags = Property.toFlags(pdesc);
if (pdesc.type() == PropertyDescriptor.GENERIC) {
- final GlobalObject global = (GlobalObject) Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
final PropertyDescriptor dDesc = global.newDataDescriptor(UNDEFINED, false, false, false);
dDesc.fillFrom((ScriptObject)pdesc);
@@ -1150,7 +1150,7 @@ public abstract class ScriptObject implements PropertyAccess {
}
setProto((ScriptObject)newProto);
} else {
- final ScriptObject global = Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
final Object newProtoObject = JSType.toScriptObject(global, newProto);
if (newProtoObject instanceof ScriptObject) {
@@ -1240,11 +1240,11 @@ public abstract class ScriptObject implements PropertyAccess {
* @return the default value
*/
public Object getDefaultValue(final Class> typeHint) {
- // We delegate to GlobalObject, as the implementation uses dynamic call sites to invoke object's "toString" and
+ // We delegate to Global, as the implementation uses dynamic call sites to invoke object's "toString" and
// "valueOf" methods, and in order to avoid those call sites from becoming megamorphic when multiple contexts
// are being executed in a long-running program, we move the code and their associated dynamic call sites
// (Global.TO_STRING and Global.VALUE_OF) into per-context code.
- return ((GlobalObject)Context.getGlobalTrusted()).getDefaultValue(this, typeHint);
+ return Context.getGlobal().getDefaultValue(this, typeHint);
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
index d9705676111..6df047d85a5 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
@@ -474,7 +474,7 @@ public final class ScriptRuntime {
* @return {@link WithObject} that is the new scope
*/
public static ScriptObject openWith(final ScriptObject scope, final Object expression) {
- final ScriptObject global = Context.getGlobalTrusted();
+ final Global global = Context.getGlobal();
if (expression == UNDEFINED) {
throw typeError(global, "cant.apply.with.to.undefined");
} else if (expression == null) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index 2c01b6d3617..edee3748b7a 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -148,7 +148,7 @@ final class SetMethodCreator {
}
private SetMethod createGlobalPropertySetter() {
- final ScriptObject global = Context.getGlobalTrusted();
+ final ScriptObject global = Context.getGlobal();
return new SetMethod(MH.filterArguments(global.addSpill(getName()), 0, ScriptObject.GLOBALFILTER), null);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 931d712b9aa..a69de45ca3d 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -34,6 +34,7 @@ import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import jdk.nashorn.internal.objects.Global;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -73,7 +74,7 @@ public final class UserAccessorProperty extends Property {
private static MethodHandle getINVOKE_UA_GETTER() {
- return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_GETTER,
+ return Context.getGlobal().getDynamicInvoker(INVOKE_UA_GETTER,
new Callable() {
@Override
public MethodHandle call() {
@@ -86,7 +87,7 @@ public final class UserAccessorProperty extends Property {
/** Dynamic invoker for setter */
private static Object INVOKE_UA_SETTER = new Object();
private static MethodHandle getINVOKE_UA_SETTER() {
- return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_SETTER,
+ return Context.getGlobal().getDynamicInvoker(INVOKE_UA_SETTER,
new Callable