Merge
authorchegar
Thu, 16 May 2013 11:47:51 +0100
changeset 18250 6a8b17cf0cd9
parent 18249 aec7e8963c3e (current diff)
parent 17346 f09ab0c41618 (diff)
child 18251 3743160a4cb8
Merge
hotspot/agent/doc/c2replay.html
langtools/make/Makefile-classic
nashorn/src/jdk/nashorn/internal/codegen/Frame.java
nashorn/src/jdk/nashorn/internal/ir/DoWhileNode.java
nashorn/src/jdk/nashorn/internal/ir/LabeledNode.java
--- a/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 1872c12529090e1c1dbf567f02ad7ae6231b8f0c jdk8-b85
 da9a4c9312816451884aa6db6f18be51a07bff13 jdk8-b86
 5ebf6c63714de2c9dcf831074086d31daec819df jdk8-b87
+e517701a4d0e25ae9c7945bca6e1762a8c5d8aa6 jdk8-b88
+4dec41b3c5e3bb616f0c6f15830d940905aa5d16 jdk8-b89
--- a/.hgtags-top-repo	Wed May 08 11:22:25 2013 +0100
+++ b/.hgtags-top-repo	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 7fc358f5943676b82f1dccd3152b1ac07d92e38b jdk8-b85
 df9b5240f0a76c91cfe1a5b39da4d08df56e05be jdk8-b86
 b9415faa7066a4d3b16d466556d5428446918d95 jdk8-b87
+e1a929afcfc492470d50be0b6b0e8dc77d3760b9 jdk8-b88
+892a0196d10c67f3a12f0eefb0bb536e423d8868 jdk8-b89
--- a/common/makefiles/NativeCompilation.gmk	Wed May 08 11:22:25 2013 +0100
+++ b/common/makefiles/NativeCompilation.gmk	Thu May 16 11:47:51 2013 +0100
@@ -411,6 +411,8 @@
             $1_EXTRA_LDFLAGS+="-implib:$$($1_OBJECT_DIR)/$$($1_LIBRARY).lib"
         endif
 
+        $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)        
+
         ifneq (,$$($1_DEBUG_SYMBOLS))
             ifeq ($(ENABLE_DEBUG_SYMBOLS), true)
                 ifeq ($(OPENJDK_TARGET_OS), windows)
@@ -549,6 +551,8 @@
             endif
         endif
 
+        $1_EXTRA_LDFLAGS_SUFFIX += $(GLOBAL_LDFLAGS_SUFFIX)
+
         $$($1_TARGET) : $$($1_EXPECTED_OBJS) $$($1_RES) $$($1_GEN_MANIFEST)
 	    	$$(call LINKING_EXE_MSG,$$($1_BASENAME))
 		$$($1_LDEXE) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $(EXE_OUT_OPTION)$$($1_TARGET) \
--- a/common/makefiles/javadoc/CORE_PKGS.gmk	Wed May 08 11:22:25 2013 +0100
+++ b/common/makefiles/javadoc/CORE_PKGS.gmk	Thu May 16 11:47:51 2013 +0100
@@ -142,6 +142,7 @@
   java.util.prefs                                \
   java.util.regex                                \
   java.util.spi                                  \
+  java.util.stream                               \
   java.util.zip                                  \
   javax.accessibility                            \
   javax.activation                               \
--- a/common/makefiles/javadoc/Javadoc.gmk	Wed May 08 11:22:25 2013 +0100
+++ b/common/makefiles/javadoc/Javadoc.gmk	Thu May 16 11:47:51 2013 +0100
@@ -390,6 +390,17 @@
 	  $(call OptionPair,-tag,specdefault:X)				; \
 	  $(call OptionPair,-tag,Note:X)				; \
 	  $(call OptionPair,-tag,ToDo:X)				; \
+          $(call OptionPair,-tag,apiNote:a:API Note:)                   ; \
+          $(call OptionPair,-tag,implSpec:a:Implementation Requirements:) ; \
+          $(call OptionPair,-tag,implNote:a:Implementation Note:)       ; \
+          $(call OptionPair,-tag,param)                                 ; \
+          $(call OptionPair,-tag,return)                                ; \
+          $(call OptionPair,-tag,throws)                                ; \
+          $(call OptionPair,-tag,since)                                 ; \
+          $(call OptionPair,-tag,version)                               ; \
+          $(call OptionPair,-tag,serialData)                            ; \
+          $(call OptionPair,-tag,factory)                               ; \
+          $(call OptionPair,-tag,see)                                   ; \
           $(call OptionPair,-tag,$(TAG_JLS)) 				; \
 	  $(call OptionOnly,-splitIndex)				; \
 	  $(call OptionPair,-overview,$(COREAPI_OVERVIEW))		; \
--- a/corba/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/corba/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 9583a6431596bac1959d2d8828f5ea217843dd12 jdk8-b85
 44a8ce4a759f2668ff434661a93ff462ea472478 jdk8-b86
 f1709874d55a06bc3d5dfa02dbcdfbc59f4cba34 jdk8-b87
+4e3a881ebb1ee96ce0872508b0066d74f310dbfa jdk8-b88
+fe4150590ee597f4e125fea950aa3b352622cc2d jdk8-b89
--- a/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java	Wed May 08 11:22:25 2013 +0100
+++ b/corba/src/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/UnionGen.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -258,6 +258,19 @@
   {
     Vector labels = vectorizeLabels (u.branches (), true);
 
+    if (Util.javaName(utype).equals ("boolean")) {
+        stream.println( "" ) ;
+        stream.println( "  private void verifyDefault (boolean discriminator)" ) ;
+        stream.println( "  {" ) ;
+        if (labels.contains ("true"))
+            stream.println ("    if ( discriminator )");
+        else
+            stream.println ("    if ( !discriminator )");
+        stream.println( "        throw new org.omg.CORBA.BAD_OPERATION();" ) ;
+        stream.println( "  }" ) ;
+        return;
+    }
+
     stream.println( "" ) ;
     stream.println( "  private void verifyDefault( " + Util.javaName(utype) +
         " value )" ) ;
@@ -763,7 +776,7 @@
             stream.println (indent + "if (" + disName + ')');
 
             if (firstBranch == null)
-                stream.println (indent + "  throw new org.omg.CORBA.BAD_OPERATION ();");
+                stream.println (indent + "  value._default(" + disName + ");");
             else {
                 stream.println (indent + '{');
                 index = readBranch (index, indent + "  ", firstBranch.typedef.name (),
@@ -774,7 +787,7 @@
             stream.println (indent + "else");
 
             if (secondBranch == null)
-                stream.println (indent + "  throw new org.omg.CORBA.BAD_OPERATION ();");
+                stream.println (indent + "  value._default(" + disName + ");");
             else {
                 stream.println (indent + '{');
                 index = readBranch (index, indent + "  ", secondBranch.typedef.name (),
@@ -924,23 +937,25 @@
         firstBranch = secondBranch;
         secondBranch = tmp;
       }
-      stream.println (indent + "if (" + disName + ')');
-      if (firstBranch == null)
-        stream.println (indent + "  throw new org.omg.CORBA.BAD_OPERATION ();");
-      else
-      {
-        stream.println (indent + '{');
-        index = writeBranch (index, indent + "  ", name, firstBranch.typedef, stream);
-        stream.println (indent + '}');
-      }
-      stream.println (indent + "else");
-      if (secondBranch == null)
-        stream.println (indent + "  throw new org.omg.CORBA.BAD_OPERATION ();");
-      else
-      {
-        stream.println (indent + '{');
-        index = writeBranch (index, indent + "  ", name, secondBranch.typedef, stream);
-        stream.println (indent + '}');
+      if (firstBranch != null && secondBranch != null) {
+          stream.println (indent + "if (" + disName + ')');
+          stream.println (indent + '{');
+          index = writeBranch (index, indent + "  ", name, firstBranch.typedef, stream);
+          stream.println (indent + '}');
+          stream.println (indent + "else");
+          stream.println (indent + '{');
+          index = writeBranch (index, indent + "  ", name, secondBranch.typedef, stream);
+          stream.println (indent + '}');
+      } else if (firstBranch != null) {
+          stream.println (indent + "if (" + disName + ')');
+          stream.println (indent + '{');
+          index = writeBranch (index, indent + "  ", name, firstBranch.typedef, stream);
+          stream.println (indent + '}');
+      } else {
+          stream.println (indent + "if (!" + disName + ')');
+          stream.println (indent + '{');
+          index = writeBranch (index, indent + "  ", name, secondBranch.typedef, stream);
+          stream.println (indent + '}');
       }
     }
     return index;
--- a/hotspot/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -337,3 +337,7 @@
 d4c2667846607042370760e23f64c3ab9350e60d jdk8-b87
 01d5f04e64dc2d64625b2db2056f5ed4de918a45 hs25-b29
 c4af77d2045476c56fbf3f914b336bb1b7cd18af hs25-b30
+8482058e74bc8c1a890e6f3be3eff192dba6ce67 jdk8-b88
+4ec91349972255650f97bedfd07e6423e02428cf hs25-b31
+9c1fe0b419b40a9ecdd1653cc9af1b6d67a12c46 jdk8-b89
+69494caf57908ba2c8efa9eaaa472b4d1875588a hs25-b32
--- a/hotspot/agent/doc/c2replay.html	Wed May 08 11:22:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-<html>
-<head>
-<title>
-C2 Replay
-</title>
-</head>
-<body>
-
-<h1>C2 compiler replay</h1>
-<p>
-The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
-This function only exists in debug version of VM
-</p>
-<h2>Usage</h2>
-<pre> 
-First, use SA to attach to the core file, if suceeded, do
-       clhsdb>dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
-       create file replay.txt, address is address of Method, or nmethod(CodeBlob)
-       clhsdb>buildreplayjars [all | boot | app]
-       create files:
-         all:
-           app.jar, boot.jar
-         boot:
-           boot.jar
-         app:
-           app.jar
-       exit SA now.
-Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
-       java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
-       This will replay the compiling process.
-
-       With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
-
-notes:
-       1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
-       2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
-
-       Use this tool to dump VM type library:
-       vmstructsdump libjvm.so > <type_name>.db
-
-       set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/doc/cireplay.html	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,41 @@
+<html>
+<head>
+<title>
+Replay
+</title>
+</head>
+<body>
+
+<h1>Compiler replay</h1>
+<p>
+The compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
+This function only exists in debug version of VM
+</p>
+<h2>Usage</h2>
+<pre>
+First, use SA to attach to the core file, if succeeded, do
+       hsdb&gt; dumpreplaydata &lt;address&gt; | -a | &lt;thread_id&gt; [&gt; replay.txt]
+       create file replay.txt, address is address of Method, or nmethod(CodeBlob)
+       hsdb&gt; buildreplayjars [all | boot | app]
+       create files:
+         all:
+           app.jar, boot.jar
+         boot:
+           boot.jar
+         app:
+           app.jar
+       exit SA now.
+Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
+       java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=&lt;datafile&gt; -XX:+ReplayCompiles ....
+       This will replay the compiling process.
+
+       With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
+
+notes:
+       1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
+       2) If encounter error as "&lt;flag&gt;" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/&lt;os&gt;/proc/&lt;os_platform&gt;
+
+       Use this tool to dump VM type library:
+       vmstructsdump libjvm.so &gt; &lt;type_name&gt;.db
+
+       set env SA_TYPEDB=&lt;type_name&gt;.db (refer different shell for set envs)
--- a/hotspot/agent/doc/clhsdb.html	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/doc/clhsdb.html	Thu May 16 11:47:51 2013 +0100
@@ -15,7 +15,7 @@
 <p>
 There is also JavaScript based SA command line interface called <a href="jsdb.html">jsdb</a>.
 But, CLHSDB supports Unix shell-like (or dbx/gdb-like) command line interface with
-support for output redirection/appending (familiar >, >>), command history and so on.
+support for output redirection/appending (familiar &gt;, &gt;&gt;), command history and so on.
 Each CLHSDB command can have zero or more arguments and optionally end with output redirection
 (or append) to a file. Commands may be stored in a file and run using <b>source</b> command.
 <b>help</b> command prints usage message for all supported commands (or a specific command)
@@ -49,7 +49,7 @@
   dumpheap [ file ] <font color="red">dump heap in hprof binary format</font>
   dumpideal -a | id <font color="red">dump ideal graph like debug flag -XX:+PrintIdeal</font>
   dumpilt -a | id <font color="red">dump inline tree for C2 compilation</font>
-  dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
+  dumpreplaydata &lt;address&gt; | -a | &lt;thread_id&gt; [&gt;replay.txt] <font color="red">dump replay data into a file</font>
   echo [ true | false ] <font color="red">turn on/off command echo mode</font>
   examine [ address/count ] | [ address,address] <font color="red">show contents of memory from given address</font>
   field [ type [ name fieldtype isStatic offset address ] ] <font color="red">print info about a field of HotSpot type</font>
@@ -96,11 +96,11 @@
 
 <h3>JavaScript integration</h3>
 
-<p>Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set 
+<p>Few CLHSDB commands are already implemented in JavaScript. It is possible to extend CLHSDB command set
 by implementing more commands in a JavaScript file and by loading it by <b>jsload</b> command. <b>jseval</b>
 command may be used to evaluate arbitrary JavaScript expression from a string. Any JavaScript function
 may be exposed as a CLHSDB command by registering it using JavaScript <b><code>registerCommand</code></b>
-function. This function accepts command name, usage and name of the JavaScript implementation function 
+function. This function accepts command name, usage and name of the JavaScript implementation function
 as arguments.
 </p>
 
@@ -127,11 +127,11 @@
 </code>
 </pre>
 
-<h3>C2 Compilation Replay</h3>
+<h3>Compilation Replay</h3>
 <p>
 When a java process crashes in compiled method, usually a core file is saved.
-The C2 replay function can reproduce the compiling process in the core.
-<a href="c2replay.html">c2replay.html</a>
+The replay function can reproduce the compiling process in the core.
+<a href="cireplay.html">cireplay.html</a>
 
 </body>
 </html>
--- a/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/os/bsd/MacosxDebuggerLocal.m	Thu May 16 11:47:51 2013 +0100
@@ -204,7 +204,7 @@
   jstring objectName, jstring symbolName) 
 {
   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
-  if (ph->core != NULL) {
+  if (ph != NULL && ph->core != NULL) {
     return lookupByNameIncore(env, ph, this_obj, objectName, symbolName);
   }
 
@@ -238,10 +238,13 @@
   const char* sym = NULL;
 
   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
-  sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
-  if (sym == NULL) return 0;
-  return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
+  if (ph != NULL && ph->core != NULL) {
+    sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
+    if (sym == NULL) return 0;
+    return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
                           (*env)->NewStringUTF(env, sym), (jlong)offset);
+  }
+  return 0;
 }
 
 /** called from Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 */
@@ -279,7 +282,7 @@
   jbyteArray array;
 
   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
-  if (ph->core != NULL) {
+  if (ph != NULL && ph->core != NULL) {
     return readBytesFromCore(env, ph, this_obj, addr, numBytes);
   }
 
@@ -394,9 +397,9 @@
 /* For core file only, called from
  * Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_getThreadIntegerRegisterSet0
  */
-jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id) {
+jlongArray getThreadIntegerRegisterSetFromCore(JNIEnv *env, jobject this_obj, long lwp_id, struct ps_prochandle* ph) {
   if (!_threads_filled)  {
-    if (!fill_java_threads(env, this_obj, get_proc_handle(env, this_obj))) {
+    if (!fill_java_threads(env, this_obj, ph)) {
       throw_new_debugger_exception(env, "Failed to fill in threads");
       return 0;
     } else {
@@ -409,7 +412,6 @@
   jlongArray array;
   jlong *regs;
 
-  struct ps_prochandle* ph = get_proc_handle(env, this_obj);
   if (get_lwp_regs(ph, lwp_id, &gregs) != true) {
     THROW_NEW_DEBUGGER_EXCEPTION_("get_thread_regs failed for a lwp", 0);
   }
@@ -521,8 +523,8 @@
   print_debug("getThreadRegisterSet0 called\n");
 
   struct ps_prochandle* ph = get_proc_handle(env, this_obj);
-  if (ph->core != NULL) {
-    return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id);
+  if (ph != NULL && ph->core != NULL) {
+    return getThreadIntegerRegisterSetFromCore(env, this_obj, thread_id, ph);
   }
 
   kern_return_t result;
@@ -705,8 +707,8 @@
   task_t gTask = 0;
   result = task_for_pid(mach_task_self(), jpid, &gTask);
   if (result != KERN_SUCCESS) {
-    print_error("attach: task_for_pid(%d) failed (%d)\n", (int)jpid, result);
-    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
+    print_error("attach: task_for_pid(%d) failed: '%s' (%d)\n", (int)jpid, mach_error_string(result), result);
+    THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process. Could be caused by an incorrect pid or lack of privileges.");
   }
   putTask(env, this_obj, gTask);
 
--- a/hotspot/agent/src/os/bsd/ps_core.c	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/os/bsd/ps_core.c	Thu May 16 11:47:51 2013 +0100
@@ -199,10 +199,10 @@
 //---------------------------------------------------------------
 // Part of the class sharing workaround:
 //
-// With class sharing, pages are mapped from classes[_g].jsa file.
+// With class sharing, pages are mapped from classes.jsa file.
 // The read-only class sharing pages are mapped as MAP_SHARED,
 // PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes[_g].jsa.
+// With this workaround, these pages are read from classes.jsa.
 
 // FIXME: !HACK ALERT!
 // The format of sharing achive file header is needed to read shared heap
@@ -298,14 +298,12 @@
   lib_info* lib = ph->libs;
   while (lib != NULL) {
     // we are iterating over shared objects from the core dump. look for
-    // libjvm[_g].so.
+    // libjvm.so.
     const char *jvm_name = 0;
 #ifdef __APPLE__
-    if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0 ||
-        (jvm_name = strstr(lib->name, "/libjvm_g.dylib")) != 0)
+    if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0)
 #else
-    if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
-        (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0)
+    if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0)
 #endif // __APPLE__
     {
       char classes_jsa[PATH_MAX];
@@ -389,7 +387,7 @@
       }
 
       ph->core->classes_jsa_fd = fd;
-      // add read-only maps from classes[_g].jsa to the list of maps
+      // add read-only maps from classes.jsa to the list of maps
       for (m = 0; m < NUM_SHARED_MAPS; m++) {
         if (header._space[m]._read_only) {
           base = (uintptr_t) header._space[m]._base;
--- a/hotspot/agent/src/os/linux/ps_core.c	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/os/linux/ps_core.c	Thu May 16 11:47:51 2013 +0100
@@ -195,10 +195,10 @@
 //---------------------------------------------------------------
 // Part of the class sharing workaround:
 //
-// With class sharing, pages are mapped from classes[_g].jsa file.
+// With class sharing, pages are mapped from classes.jsa file.
 // The read-only class sharing pages are mapped as MAP_SHARED,
 // PROT_READ pages. These pages are not dumped into core dump.
-// With this workaround, these pages are read from classes[_g].jsa.
+// With this workaround, these pages are read from classes.jsa.
 
 // FIXME: !HACK ALERT!
 // The format of sharing achive file header is needed to read shared heap
@@ -284,10 +284,9 @@
    lib_info* lib = ph->libs;
    while (lib != NULL) {
       // we are iterating over shared objects from the core dump. look for
-      // libjvm[_g].so.
+      // libjvm.so.
       const char *jvm_name = 0;
-      if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0 ||
-          (jvm_name = strstr(lib->name, "/libjvm_g.so")) != 0) {
+      if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0) {
          char classes_jsa[PATH_MAX];
          struct FileMapHeader header;
          size_t n = 0;
@@ -371,7 +370,7 @@
          }
 
          ph->core->classes_jsa_fd = fd;
-         // add read-only maps from classes[_g].jsa to the list of maps
+         // add read-only maps from classes.jsa to the list of maps
          for (m = 0; m < NUM_SHARED_MAPS; m++) {
             if (header._space[m]._read_only) {
                base = (uintptr_t) header._space[m]._base;
--- a/hotspot/agent/src/os/solaris/proc/saproc.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/os/solaris/proc/saproc.cpp	Thu May 16 11:47:51 2013 +0100
@@ -589,8 +589,7 @@
   JNIEnv*   env = dbg->env;
   jobject this_obj = dbg->this_obj;
   const char* jvm_name = 0;
-  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL ||
-      (jvm_name = strstr(obj_name, "libjvm_g.so")) != NULL) {
+  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) {
     jvm_name = obj_name;
   } else {
     return 0;
@@ -598,7 +597,7 @@
 
   struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
 
-  // initialize classes[_g].jsa file descriptor field.
+  // initialize classes.jsa file descriptor field.
   dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
 
   // check whether class sharing is on by reading variable "UseSharedSpaces"
@@ -641,7 +640,7 @@
 
   print_debug("looking for %s\n", classes_jsa);
 
-  // open the classes[_g].jsa
+  // open the classes.jsa
   int fd = libsaproc_open(classes_jsa, O_RDONLY);
   if (fd < 0) {
     char errMsg[ERR_MSG_SIZE];
@@ -651,7 +650,7 @@
     print_debug("opened shared archive file %s\n", classes_jsa);
   }
 
-  // parse classes[_g].jsa
+  // parse classes.jsa
   struct FileMapHeader* pheader = (struct FileMapHeader*) malloc(sizeof(struct FileMapHeader));
   if (pheader == NULL) {
     close(fd);
@@ -798,8 +797,8 @@
   if (! isProcess) {
     /*
      * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
-     * These pages are mapped from the file "classes[_g].jsa". MAP_SHARED pages are not dumped
-     * in Solaris core.To read shared heap pages, we have to read classes[_g].jsa file.
+     * These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped
+     * in Solaris core.To read shared heap pages, we have to read classes.jsa file.
      */
     Pobject_iter(ph, init_classsharing_workaround, &dbg);
     exception = env->ExceptionOccurred();
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HotSpotAgent.java	Thu May 16 11:47:51 2013 +0100
@@ -24,20 +24,29 @@
 
 package sun.jvm.hotspot;
 
-import java.io.PrintStream;
-import java.net.*;
-import java.rmi.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.bsd.*;
-import sun.jvm.hotspot.debugger.proc.*;
-import sun.jvm.hotspot.debugger.remote.*;
-import sun.jvm.hotspot.debugger.windbg.*;
-import sun.jvm.hotspot.debugger.linux.*;
-import sun.jvm.hotspot.memory.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.utilities.*;
+import java.rmi.RemoteException;
+
+import sun.jvm.hotspot.debugger.Debugger;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.JVMDebugger;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.MachineDescriptionAMD64;
+import sun.jvm.hotspot.debugger.MachineDescriptionIA64;
+import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86;
+import sun.jvm.hotspot.debugger.MachineDescriptionSPARC32Bit;
+import sun.jvm.hotspot.debugger.MachineDescriptionSPARC64Bit;
+import sun.jvm.hotspot.debugger.NoSuchSymbolException;
+import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
+import sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal;
+import sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal;
+import sun.jvm.hotspot.debugger.remote.RemoteDebugger;
+import sun.jvm.hotspot.debugger.remote.RemoteDebuggerClient;
+import sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer;
+import sun.jvm.hotspot.debugger.windbg.WindbgDebuggerLocal;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.utilities.PlatformInfo;
+import sun.jvm.hotspot.utilities.UnsupportedPlatformException;
 
 /** <P> This class wraps much of the basic functionality and is the
  * highest-level factory for VM data structures. It makes it simple
@@ -475,7 +484,7 @@
     }
 
     private void setupJVMLibNamesSolaris() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so", "gamma_g" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -507,7 +516,7 @@
     }
 
     private void setupJVMLibNamesWin32() {
-        jvmLibNames = new String[] { "jvm.dll", "jvm_g.dll" };
+        jvmLibNames = new String[] { "jvm.dll" };
     }
 
     //
@@ -547,7 +556,7 @@
     }
 
     private void setupJVMLibNamesLinux() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -572,7 +581,7 @@
     }
 
     private void setupJVMLibNamesBsd() {
-        jvmLibNames = new String[] { "libjvm.so", "libjvm_g.so" };
+        jvmLibNames = new String[] { "libjvm.so" };
     }
 
     //
@@ -595,7 +604,7 @@
     }
 
     private void setupJVMLibNamesDarwin() {
-        jvmLibNames = new String[] { "libjvm.dylib", "libjvm_g.dylib" };
+        jvmLibNames = new String[] { "libjvm.dylib" };
     }
 
     /** Convenience routine which should be called by per-platform
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/LinuxVtblAccess.java	Thu May 16 11:47:51 2013 +0100
@@ -24,9 +24,9 @@
 
 package sun.jvm.hotspot;
 
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.types.basic.*;
+import sun.jvm.hotspot.debugger.SymbolLookup;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.basic.BasicVtblAccess;
 
 public class LinuxVtblAccess extends BasicVtblAccess {
   private String vt;
@@ -35,8 +35,7 @@
                          String[] dllNames) {
     super(symbolLookup, dllNames);
 
-    if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null ||
-        symbolLookup.lookup("libjvm_g.so", "__vt_10JavaThread") != null) {
+    if (symbolLookup.lookup("libjvm.so", "__vt_10JavaThread") != null) {
        // old C++ ABI
        vt = "__vt_";
     } else {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java	Thu May 16 11:47:51 2013 +0100
@@ -93,10 +93,11 @@
     CompileTask task = task();
     Method method = task.method();
     int entryBci = task.osrBci();
+    int compLevel = task.compLevel();
     Klass holder = method.getMethodHolder();
     out.println("compile " + holder.getName().asString() + " " +
                 OopUtilities.escapeString(method.getName().asString()) + " " +
                 method.getSignature().asString() + " " +
-                entryBci);
+                entryBci + " " + compLevel);
   }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Thu May 16 11:47:51 2013 +0100
@@ -78,6 +78,8 @@
       current sweep traversal index. */
   private static CIntegerField stackTraversalMarkField;
 
+  private static CIntegerField compLevelField;
+
   static {
     VM.registerVMInitializedObserver(new Observer() {
         public void update(Observable o, Object data) {
@@ -113,7 +115,7 @@
     osrEntryPointField          = type.getAddressField("_osr_entry_point");
     lockCountField              = type.getJIntField("_lock_count");
     stackTraversalMarkField     = type.getCIntegerField("_stack_traversal_mark");
-
+    compLevelField              = type.getCIntegerField("_comp_level");
     pcDescSize = db.lookupType("PcDesc").getSize();
   }
 
@@ -530,7 +532,7 @@
     out.println("compile " + holder.getName().asString() + " " +
                 OopUtilities.escapeString(method.getName().asString()) + " " +
                 method.getSignature().asString() + " " +
-                getEntryBCI());
+                getEntryBCI() + " " + getCompLevel());
 
   }
 
@@ -551,4 +553,5 @@
   private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); }
   private int getNulChkTableOffset()  { return (int) nulChkTableOffsetField .getValue(addr); }
   private int getNMethodEndOffset()   { return (int) nmethodEndOffsetField  .getValue(addr); }
+  private int getCompLevel()          { return (int) compLevelField         .getValue(addr); }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java	Thu May 16 11:47:51 2013 +0100
@@ -46,10 +46,12 @@
     Type type      = db.lookupType("CompileTask");
     methodField = type.getAddressField("_method");
     osrBciField = new CIntField(type.getCIntegerField("_osr_bci"), 0);
+    compLevelField = new CIntField(type.getCIntegerField("_comp_level"), 0);
   }
 
   private static AddressField methodField;
   private static CIntField osrBciField;
+  private static CIntField compLevelField;
 
   public CompileTask(Address addr) {
     super(addr);
@@ -63,4 +65,8 @@
   public int osrBci() {
     return (int)osrBciField.getValue(getAddress());
   }
+
+  public int compLevel() {
+      return (int)compLevelField.getValue(getAddress());
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java	Thu May 16 11:47:51 2013 +0100
@@ -24,17 +24,28 @@
 
 package sun.jvm.hotspot.debugger.bsd;
 
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.x86.*;
-import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.utilities.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.DebuggerBase;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.DebuggerUtilities;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.NotInHeapException;
+import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.debugger.ReadResult;
+import sun.jvm.hotspot.debugger.ThreadProxy;
+import sun.jvm.hotspot.debugger.UnalignedAddressException;
+import sun.jvm.hotspot.debugger.UnmappedAddressException;
+import sun.jvm.hotspot.debugger.cdbg.CDebugger;
+import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol;
+import sun.jvm.hotspot.debugger.cdbg.LoadObject;
+import sun.jvm.hotspot.runtime.JavaThread;
+import sun.jvm.hotspot.runtime.Threads;
 import sun.jvm.hotspot.runtime.VM;
-import sun.jvm.hotspot.runtime.Threads;
-import sun.jvm.hotspot.runtime.JavaThread;
-import java.lang.reflect.*;
+import sun.jvm.hotspot.utilities.PlatformInfo;
 
 /** <P> An implementation of the JVMDebugger interface. The basic debug
     facilities are implemented through ptrace interface in the JNI code
@@ -246,10 +257,8 @@
     /* called from attach methods */
     private void findABIVersion() throws DebuggerException {
         String libjvmName = isDarwin ? "libjvm.dylib" : "libjvm.so";
-        String libjvm_gName = isDarwin? "libjvm_g.dylib" : "libjvm_g.so";
         String javaThreadVt = isDarwin ? "_vt_10JavaThread" : "__vt_10JavaThread";
-        if (lookupByName0(libjvmName, javaThreadVt) != 0 ||
-            lookupByName0(libjvm_gName, javaThreadVt) != 0) {
+        if (lookupByName0(libjvmName, javaThreadVt) != 0) {
             // old C++ ABI
             useGCC32ABI = false;
         } else {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java	Thu May 16 11:47:51 2013 +0100
@@ -24,14 +24,25 @@
 
 package sun.jvm.hotspot.debugger.linux;
 
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.debugger.x86.*;
-import sun.jvm.hotspot.debugger.cdbg.*;
-import sun.jvm.hotspot.utilities.*;
-import java.lang.reflect.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.debugger.DebuggerBase;
+import sun.jvm.hotspot.debugger.DebuggerException;
+import sun.jvm.hotspot.debugger.DebuggerUtilities;
+import sun.jvm.hotspot.debugger.MachineDescription;
+import sun.jvm.hotspot.debugger.NotInHeapException;
+import sun.jvm.hotspot.debugger.OopHandle;
+import sun.jvm.hotspot.debugger.ReadResult;
+import sun.jvm.hotspot.debugger.ThreadProxy;
+import sun.jvm.hotspot.debugger.UnalignedAddressException;
+import sun.jvm.hotspot.debugger.UnmappedAddressException;
+import sun.jvm.hotspot.debugger.cdbg.CDebugger;
+import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol;
+import sun.jvm.hotspot.debugger.cdbg.LoadObject;
+import sun.jvm.hotspot.utilities.PlatformInfo;
 
 /** <P> An implementation of the JVMDebugger interface. The basic debug
     facilities are implemented through ptrace interface in the JNI code
@@ -238,8 +249,7 @@
 
     /* called from attach methods */
     private void findABIVersion() throws DebuggerException {
-        if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0 ||
-            lookupByName0("libjvm_g.so", "__vt_10JavaThread") != 0) {
+        if (lookupByName0("libjvm.so", "__vt_10JavaThread") != 0) {
             // old C++ ABI
             useGCC32ABI = false;
         } else {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java	Thu May 16 11:47:51 2013 +0100
@@ -117,8 +117,6 @@
                 mode = MODE_HEAP_SUMMARY;
             } else if (modeFlag.equals("-histo")) {
                 mode = MODE_HISTOGRAM;
-            } else if (modeFlag.equals("-permstat")) {
-                mode = MODE_CLSTATS;
             } else if (modeFlag.equals("-clstats")) {
                 mode = MODE_CLSTATS;
             } else if (modeFlag.equals("-finalizerinfo")) {
--- a/hotspot/make/excludeSrc.make	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/make/excludeSrc.make	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+# 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
@@ -81,22 +81,25 @@
 	cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \
 	cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp compactibleFreeListSpace.cpp \
 	concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp \
-	freeChunk.cpp adaptiveFreeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \
-	concurrentG1Refine.cpp concurrentG1RefineThread.cpp concurrentMark.cpp concurrentMarkThread.cpp \
-	dirtyCardQueue.cpp g1AllocRegion.cpp g1BlockOffsetTable.cpp g1CollectedHeap.cpp g1GCPhaseTimes.cpp \
-	g1CollectorPolicy.cpp g1ErgoVerbose.cpp g1_globals.cpp g1HRPrinter.cpp g1MarkSweep.cpp \
-	g1MMUTracker.cpp g1MonitoringSupport.cpp g1RemSet.cpp g1SATBCardTableModRefBS.cpp heapRegion.cpp \
-	heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp ptrQueue.cpp \
-	satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp adjoiningGenerations.cpp \
-	adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp cardTableExtension.cpp \
-	gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp parallelScavengeHeap.cpp parMarkBitMap.cpp \
-	pcTasks.cpp psAdaptiveSizePolicy.cpp psCompactionManager.cpp psGCAdaptivePolicyCounters.cpp \
-	psGenerationCounters.cpp psMarkSweep.cpp psMarkSweepDecorator.cpp psOldGen.cpp psParallelCompact.cpp \
-	psPromotionLAB.cpp psPromotionManager.cpp psScavenge.cpp psTasks.cpp psVirtualspace.cpp \
-	psYoungGen.cpp vmPSOperations.cpp asParNewGeneration.cpp parCardTableModRefBS.cpp \
-	parGCAllocBuffer.cpp parNewGeneration.cpp mutableSpace.cpp gSpaceCounters.cpp allocationStats.cpp \
-	spaceCounters.cpp gcAdaptivePolicyCounters.cpp mutableNUMASpace.cpp immutableSpace.cpp \
-	immutableSpace.cpp g1MemoryPool.cpp psMemoryPool.cpp yieldingWorkGroup.cpp g1Log.cpp
+	freeChunk.cpp adaptiveFreeList.cpp promotionInfo.cpp vmCMSOperations.cpp \
+	collectionSetChooser.cpp concurrentG1Refine.cpp concurrentG1RefineThread.cpp \
+	concurrentMark.cpp concurrentMarkThread.cpp dirtyCardQueue.cpp g1AllocRegion.cpp \
+	g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \
+	g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \
+	g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp \
+	g1RemSet.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \
+	heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \
+	ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \
+	adjoiningGenerations.cpp adjoiningVirtualSpaces.cpp asPSOldGen.cpp asPSYoungGen.cpp \
+	cardTableExtension.cpp gcTaskManager.cpp gcTaskThread.cpp objectStartArray.cpp \
+	parallelScavengeHeap.cpp parMarkBitMap.cpp pcTasks.cpp psAdaptiveSizePolicy.cpp \
+	psCompactionManager.cpp psGCAdaptivePolicyCounters.cpp psGenerationCounters.cpp \
+	psMarkSweep.cpp psMarkSweepDecorator.cpp psMemoryPool.cpp psOldGen.cpp \
+	psParallelCompact.cpp psPromotionLAB.cpp psPromotionManager.cpp psScavenge.cpp \
+	psTasks.cpp psVirtualspace.cpp psYoungGen.cpp vmPSOperations.cpp asParNewGeneration.cpp \
+	parCardTableModRefBS.cpp parGCAllocBuffer.cpp parNewGeneration.cpp mutableSpace.cpp \
+	gSpaceCounters.cpp allocationStats.cpp spaceCounters.cpp gcAdaptivePolicyCounters.cpp \
+	mutableNUMASpace.cpp immutableSpace.cpp yieldingWorkGroup.cpp
 endif 
 
 ifeq ($(INCLUDE_NMT), false)
--- a/hotspot/make/hotspot_version	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/make/hotspot_version	Thu May 16 11:47:51 2013 +0100
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=25
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=30
+HS_BUILD_NUMBER=32
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=8
--- a/hotspot/make/windows/makefiles/compile.make	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/make/windows/makefiles/compile.make	Thu May 16 11:47:51 2013 +0100
@@ -52,7 +52,7 @@
 # improving the quality of crash log stack traces involving jvm.dll.
 
 # These are always used in all compiles
-CXX_FLAGS=/nologo /W3 /WX
+CXX_FLAGS=$(EXTRA_CFLAGS) /nologo /W3 /WX
 
 # Let's add debug information when Full Debug Symbols is enabled
 !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1"
--- a/hotspot/make/windows/makefiles/defs.make	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/make/windows/makefiles/defs.make	Thu May 16 11:47:51 2013 +0100
@@ -193,7 +193,7 @@
   MAKE_ARGS += JDK_BUILD_NUMBER=$(COOKED_BUILD_NUMBER)
 endif
 
-NMAKE= MAKEFLAGS= MFLAGS= nmake -NOLOGO
+NMAKE= MAKEFLAGS= MFLAGS= EXTRA_CFLAGS="$(EXTRA_CFLAGS)" nmake -NOLOGO
 ifndef SYSTEM_UNAME
   SYSTEM_UNAME := $(shell uname)
   export SYSTEM_UNAME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+#ifdef COMPILER2
+#include "opto/matcher.hpp"
+#endif
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  if (is_icholder_entry(call->destination())) {
+    NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+    InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+  }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+  : _ic_call(call)
+{
+  address ic_call = call->instruction_address();
+
+  assert(ic_call != NULL, "ic_call address must be set");
+  assert(nm != NULL, "must pass nmethod");
+  assert(nm->contains(ic_call), "must be in nmethod");
+
+  // Search for the ic_call at the given address.
+  RelocIterator iter(nm, ic_call, ic_call+1);
+  bool ret = iter.next();
+  assert(ret == true, "relocInfo must exist at this address");
+  assert(iter.addr() == ic_call, "must find ic_call");
+  if (iter.type() == relocInfo::virtual_call_type) {
+    virtual_call_Relocation* r = iter.virtual_call_reloc();
+    _is_optimized = false;
+    _value = nativeMovConstReg_at(r->cached_value());
+  } else {
+    assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+    _is_optimized = true;
+    _value = NULL;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+#define __ _masm.
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+#ifdef COMPILER2
+  // Stub is fixed up when the corresponding call is converted from calling
+  // compiled code to calling interpreted code.
+  // set (empty), G5
+  // jmp -1
+
+  address mark = cbuf.insts_mark();  // Get mark within main instrs section.
+
+  MacroAssembler _masm(&cbuf);
+
+  address base =
+  __ start_a_stub(to_interp_stub_size()*2);
+  if (base == NULL) return;  // CodeBuffer::expand failed.
+
+  // Static stub relocation stores the instruction address of the call.
+  __ relocate(static_stub_Relocation::spec(mark));
+
+  __ set_metadata(NULL, as_Register(Matcher::inline_cache_reg_encode()));
+
+  __ set_inst_mark();
+  AddressLiteral addrlit(-1);
+  __ JUMP(addrlit, G3, 0);
+
+  __ delayed()->nop();
+
+  // Update current stubs pointer and restore code_end.
+  __ end_a_stub();
+#else
+  ShouldNotReachHere();
+#endif
+}
+#undef __
+
+int CompiledStaticCall::to_interp_stub_size() {
+  // This doesn't need to be accurate but it must be larger or equal to
+  // the real size of the stub.
+  return (NativeMovConstReg::instruction_size +  // sethi/setlo;
+          NativeJump::instruction_size + // sethi; jmp; nop
+          (TraceJumps ? 20 * BytesPerInstWord : 0) );
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+  return 10;  // 4 in emit_java_to_interp + 1 in Java_Static_Call
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+  address stub = find_stub();
+  guarantee(stub != NULL, "stub not found");
+
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+                  instruction_address(),
+                  callee->name_and_sig_as_C_string());
+  }
+
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+  assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
+         "a) MT-unsafe modification of inline cache");
+  assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
+         "b) MT-unsafe modification of inline cache");
+
+  // Update stub.
+  method_holder->set_data((intptr_t)callee());
+  jump->set_jump_destination(entry);
+
+  // Update jump to call.
+  set_destination_mt_safe(stub);
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  // Reset stub.
+  address stub = static_stub->addr();
+  assert(stub != NULL, "stub not found");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+  method_holder->set_data(0);
+  jump->set_jump_destination((address)-1);
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+  // Verify call.
+  NativeCall::verify();
+  if (os::is_MP()) {
+    verify_alignment();
+  }
+
+  // Verify stub.
+  address stub = find_stub();
+  assert(stub != NULL, "no stub found for static call");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+  // Verify state.
+  assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp	Thu May 16 11:47:51 2013 +0100
@@ -30,4 +30,6 @@
 
 const int StackAlignmentInBytes = (2*wordSize);
 
+#define SUPPORTS_NATIVE_CX8
+
 #endif // CPU_SPARC_VM_GLOBALDEFINITIONS_SPARC_HPP
--- a/hotspot/src/cpu/sparc/vm/jni_sparc.h	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/sparc/vm/jni_sparc.h	Thu May 16 11:47:51 2013 +0100
@@ -23,7 +23,12 @@
  * questions.
  */
 
-#if defined(__GNUC__) && (__GNUC__ >= 4)
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/hotspot/src/cpu/sparc/vm/sparc.ad	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad	Thu May 16 11:47:51 2013 +0100
@@ -1656,53 +1656,6 @@
 }
 
 //=============================================================================
-
-// emit call stub, compiled java to interpretor
-void emit_java_to_interp(CodeBuffer &cbuf ) {
-
-  // Stub is fixed up when the corresponding call is converted from calling
-  // compiled code to calling interpreted code.
-  // set (empty), G5
-  // jmp -1
-
-  address mark = cbuf.insts_mark();  // get mark within main instrs section
-
-  MacroAssembler _masm(&cbuf);
-
-  address base =
-  __ start_a_stub(Compile::MAX_stubs_size);
-  if (base == NULL)  return;  // CodeBuffer::expand failed
-
-  // static stub relocation stores the instruction address of the call
-  __ relocate(static_stub_Relocation::spec(mark));
-
-  __ set_metadata(NULL, reg_to_register_object(Matcher::inline_cache_reg_encode()));
-
-  __ set_inst_mark();
-  AddressLiteral addrlit(-1);
-  __ JUMP(addrlit, G3, 0);
-
-  __ delayed()->nop();
-
-  // Update current stubs pointer and restore code_end.
-  __ end_a_stub();
-}
-
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp() {
-  // This doesn't need to be accurate but it must be larger or equal to
-  // the real size of the stub.
-  return (NativeMovConstReg::instruction_size +  // sethi/setlo;
-          NativeJump::instruction_size + // sethi; jmp; nop
-          (TraceJumps ? 20 * BytesPerInstWord : 0) );
-}
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp() {
-  return 10;  // 4 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-
-//=============================================================================
 #ifndef PRODUCT
 void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
   st->print_cr("\nUEP:");
@@ -2576,15 +2529,15 @@
   enc_class Java_Static_Call (method meth) %{    // JAVA STATIC CALL
     // CALL to fixup routine.  Fixup routine uses ScopeDesc info to determine
     // who we intended to call.
-    if ( !_method ) {
+    if (!_method) {
       emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type);
     } else if (_optimized_virtual) {
       emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type);
     } else {
       emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type);
     }
-    if( _method ) {  // Emit stub for static call
-      emit_java_to_interp(cbuf);
+    if (_method) {  // Emit stub for static call.
+      CompiledStaticCall::emit_to_interp_stub(cbuf);
     }
   %}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/safepoint.hpp"
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  if (is_icholder_entry(call->destination())) {
+    NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+    InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+  }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+  : _ic_call(call)
+{
+  address ic_call = call->instruction_address();
+
+  assert(ic_call != NULL, "ic_call address must be set");
+  assert(nm != NULL, "must pass nmethod");
+  assert(nm->contains(ic_call), "must be in nmethod");
+
+  // Search for the ic_call at the given address.
+  RelocIterator iter(nm, ic_call, ic_call+1);
+  bool ret = iter.next();
+  assert(ret == true, "relocInfo must exist at this address");
+  assert(iter.addr() == ic_call, "must find ic_call");
+  if (iter.type() == relocInfo::virtual_call_type) {
+    virtual_call_Relocation* r = iter.virtual_call_reloc();
+    _is_optimized = false;
+    _value = nativeMovConstReg_at(r->cached_value());
+  } else {
+    assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+    _is_optimized = true;
+    _value = NULL;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+#define __ _masm.
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+  // Stub is fixed up when the corresponding call is converted from
+  // calling compiled code to calling interpreted code.
+  // movq rbx, 0
+  // jmp -5 # to self
+
+  address mark = cbuf.insts_mark();  // Get mark within main instrs section.
+
+  // Note that the code buffer's insts_mark is always relative to insts.
+  // That's why we must use the macroassembler to generate a stub.
+  MacroAssembler _masm(&cbuf);
+
+  address base =
+  __ start_a_stub(to_interp_stub_size()*2);
+  if (base == NULL) return;  // CodeBuffer::expand failed.
+  // Static stub relocation stores the instruction address of the call.
+  __ relocate(static_stub_Relocation::spec(mark), Assembler::imm_operand);
+  // Static stub relocation also tags the Method* in the code-stream.
+  __ mov_metadata(rbx, (Metadata*) NULL);  // Method is zapped till fixup time.
+  // This is recognized as unresolved by relocs/nativeinst/ic code.
+  __ jump(RuntimeAddress(__ pc()));
+
+  // Update current stubs pointer and restore insts_end.
+  __ end_a_stub();
+}
+#undef __
+
+int CompiledStaticCall::to_interp_stub_size() {
+  return NOT_LP64(10)    // movl; jmp
+         LP64_ONLY(15);  // movq (1+1+8); jmp (1+4)
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+  return 4; // 3 in emit_to_interp_stub + 1 in emit_call
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+  address stub = find_stub();
+  guarantee(stub != NULL, "stub not found");
+
+  if (TraceICs) {
+    ResourceMark rm;
+    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
+                  instruction_address(),
+                  callee->name_and_sig_as_C_string());
+  }
+
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+  assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(),
+         "a) MT-unsafe modification of inline cache");
+  assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry,
+         "b) MT-unsafe modification of inline cache");
+
+  // Update stub.
+  method_holder->set_data((intptr_t)callee());
+  jump->set_jump_destination(entry);
+
+  // Update jump to call.
+  set_destination_mt_safe(stub);
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  // Reset stub.
+  address stub = static_stub->addr();
+  assert(stub != NULL, "stub not found");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+  method_holder->set_data(0);
+  jump->set_jump_destination((address)-1);
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+  // Verify call.
+  NativeCall::verify();
+  if (os::is_MP()) {
+    verify_alignment();
+  }
+
+  // Verify stub.
+  address stub = find_stub();
+  assert(stub != NULL, "no stub found for static call");
+  // Creation also verifies the object.
+  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
+  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
+
+  // Verify state.
+  assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp	Thu May 16 11:47:51 2013 +0100
@@ -27,4 +27,6 @@
 
 const int StackAlignmentInBytes  = 16;
 
+#define SUPPORTS_NATIVE_CX8
+
 #endif // CPU_X86_VM_GLOBALDEFINITIONS_X86_HPP
--- a/hotspot/src/cpu/x86/vm/jni_x86.h	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/x86/vm/jni_x86.h	Thu May 16 11:47:51 2013 +0100
@@ -28,7 +28,13 @@
 
 #if defined(SOLARIS) || defined(LINUX) || defined(_ALLBSD_SOURCE)
 
-#if defined(__GNUC__) && (__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2)
+
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/hotspot/src/cpu/x86/vm/x86_32.ad	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/x86/vm/x86_32.ad	Thu May 16 11:47:51 2013 +0100
@@ -1257,43 +1257,6 @@
 }
 
 //=============================================================================
-
-// emit call stub, compiled java to interpreter
-void emit_java_to_interp(CodeBuffer &cbuf ) {
-  // Stub is fixed up when the corresponding call is converted from calling
-  // compiled code to calling interpreted code.
-  // mov rbx,0
-  // jmp -1
-
-  address mark = cbuf.insts_mark();  // get mark within main instrs section
-
-  // Note that the code buffer's insts_mark is always relative to insts.
-  // That's why we must use the macroassembler to generate a stub.
-  MacroAssembler _masm(&cbuf);
-
-  address base =
-  __ start_a_stub(Compile::MAX_stubs_size);
-  if (base == NULL)  return;  // CodeBuffer::expand failed
-  // static stub relocation stores the instruction address of the call
-  __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM32);
-  // static stub relocation also tags the Method* in the code-stream.
-  __ mov_metadata(rbx, (Metadata*)NULL);  // method is zapped till fixup time
-  // This is recognized as unresolved by relocs/nativeInst/ic code
-  __ jump(RuntimeAddress(__ pc()));
-
-  __ end_a_stub();
-  // Update current stubs pointer and restore insts_end.
-}
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp() {
-  return 10;  // movl; jmp
-}
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp() {
-  return 4;  // 3 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-//=============================================================================
 #ifndef PRODUCT
 void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream* st ) const {
   st->print_cr(  "CMP    EAX,[ECX+4]\t# Inline cache check");
@@ -1909,8 +1872,8 @@
       emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4),
                      static_call_Relocation::spec(), RELOC_IMM32 );
     }
-    if (_method) {  // Emit stub for static call
-      emit_java_to_interp(cbuf);
+    if (_method) {  // Emit stub for static call.
+      CompiledStaticCall::emit_to_interp_stub(cbuf);
     }
   %}
 
--- a/hotspot/src/cpu/x86/vm/x86_64.ad	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/x86/vm/x86_64.ad	Thu May 16 11:47:51 2013 +0100
@@ -1388,48 +1388,6 @@
 }
 
 //=============================================================================
-
-// emit call stub, compiled java to interpreter
-void emit_java_to_interp(CodeBuffer& cbuf)
-{
-  // Stub is fixed up when the corresponding call is converted from
-  // calling compiled code to calling interpreted code.
-  // movq rbx, 0
-  // jmp -5 # to self
-
-  address mark = cbuf.insts_mark();  // get mark within main instrs section
-
-  // Note that the code buffer's insts_mark is always relative to insts.
-  // That's why we must use the macroassembler to generate a stub.
-  MacroAssembler _masm(&cbuf);
-
-  address base =
-  __ start_a_stub(Compile::MAX_stubs_size);
-  if (base == NULL)  return;  // CodeBuffer::expand failed
-  // static stub relocation stores the instruction address of the call
-  __ relocate(static_stub_Relocation::spec(mark), RELOC_IMM64);
-  // static stub relocation also tags the Method* in the code-stream.
-  __ mov_metadata(rbx, (Metadata*) NULL);  // method is zapped till fixup time
-  // This is recognized as unresolved by relocs/nativeinst/ic code
-  __ jump(RuntimeAddress(__ pc()));
-
-  // Update current stubs pointer and restore insts_end.
-  __ end_a_stub();
-}
-
-// size of call stub, compiled java to interpretor
-uint size_java_to_interp()
-{
-  return 15;  // movq (1+1+8); jmp (1+4)
-}
-
-// relocation entries for call stub, compiled java to interpretor
-uint reloc_java_to_interp()
-{
-  return 4; // 3 in emit_java_to_interp + 1 in Java_Static_Call
-}
-
-//=============================================================================
 #ifndef PRODUCT
 void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
 {
@@ -2078,8 +2036,8 @@
                      RELOC_DISP32);
     }
     if (_method) {
-      // Emit stub for static call
-      emit_java_to_interp(cbuf);
+      // Emit stub for static call.
+      CompiledStaticCall::emit_to_interp_stub(cbuf);
     }
   %}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/zero/vm/compiledIC_zero.cpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 "classfile/systemDictionary.hpp"
+#include "code/codeCache.hpp"
+#include "code/compiledIC.hpp"
+#include "code/icBuffer.hpp"
+#include "code/nmethod.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/symbol.hpp"
+#include "runtime/icache.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "utilities/events.hpp"
+
+
+// Release the CompiledICHolder* associated with this call site is there is one.
+void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  if (is_icholder_entry(call->destination())) {
+    NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
+    InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
+  }
+}
+
+bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
+  // This call site might have become stale so inspect it carefully.
+  NativeCall* call = nativeCall_at(call_site->addr());
+  return is_icholder_entry(call->destination());
+}
+
+//-----------------------------------------------------------------------------
+// High-level access to an inline cache. Guaranteed to be MT-safe.
+
+CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
+  : _ic_call(call)
+{
+  address ic_call = call->instruction_address();
+
+  assert(ic_call != NULL, "ic_call address must be set");
+  assert(nm != NULL, "must pass nmethod");
+  assert(nm->contains(ic_call), "must be in nmethod");
+
+  // Search for the ic_call at the given address.
+  RelocIterator iter(nm, ic_call, ic_call+1);
+  bool ret = iter.next();
+  assert(ret == true, "relocInfo must exist at this address");
+  assert(iter.addr() == ic_call, "must find ic_call");
+  if (iter.type() == relocInfo::virtual_call_type) {
+    virtual_call_Relocation* r = iter.virtual_call_reloc();
+    _is_optimized = false;
+    _value = nativeMovConstReg_at(r->cached_value());
+  } else {
+    assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
+    _is_optimized = true;
+    _value = NULL;
+  }
+}
+
+// ----------------------------------------------------------------------------
+
+void CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+int CompiledStaticCall::to_interp_stub_size() {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+  return 0;
+}
+
+// Relocation entries for call stub, compiled java to interpreter.
+int CompiledStaticCall::reloc_to_interp_stub() {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+  return 0;
+}
+
+void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+//-----------------------------------------------------------------------------
+// Non-product mode code.
+#ifndef PRODUCT
+
+void CompiledStaticCall::verify() {
+  ShouldNotReachHere(); // Only needed for COMPILER2.
+}
+
+#endif // !PRODUCT
--- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp	Thu May 16 11:47:51 2013 +0100
@@ -212,7 +212,13 @@
 
   // Update the invocation counter
   if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) {
-    InvocationCounter *counter = method->invocation_counter();
+    MethodCounters* mcs = method->method_counters();
+    if (mcs == NULL) {
+      CALL_VM_NOCHECK(mcs = InterpreterRuntime::build_method_counters(thread, method));
+      if (HAS_PENDING_EXCEPTION)
+        goto unwind_and_return;
+    }
+    InvocationCounter *counter = mcs->invocation_counter();
     counter->increment();
     if (counter->reached_InvocationLimit()) {
       CALL_VM_NOCHECK(
--- a/hotspot/src/cpu/zero/vm/jni_zero.h	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/cpu/zero/vm/jni_zero.h	Thu May 16 11:47:51 2013 +0100
@@ -25,7 +25,13 @@
  */
 
 
-#if defined(__GNUC__) && (__GNUC__ >= 4)
+
+// Note: please do not change these without also changing jni_md.h in the JDK
+// repository
+#ifndef __has_attribute
+  #define __has_attribute(x) 0
+#endif
+#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
   #define JNIEXPORT     __attribute__((visibility("default")))
   #define JNIIMPORT     __attribute__((visibility("default")))
 #else
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1230,10 +1230,6 @@
   return retval;
 }
 
-const char* os::get_current_directory(char *buf, int buflen) {
-  return getcwd(buf, buflen);
-}
-
 // check if addr is inside libjvm.so
 bool os::address_is_in_vm(address addr) {
   static address libjvm_base_addr;
@@ -2080,9 +2076,10 @@
     flags |= MAP_FIXED;
   }
 
-  // Map uncommitted pages PROT_READ and PROT_WRITE, change access
-  // to PROT_EXEC if executable when we commit the page.
-  addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
+  // Map reserved/uncommitted pages PROT_NONE so we fail early if we
+  // touch an uncommitted page. Otherwise, the read/write might
+  // succeed if we have enough swap space to back the physical page.
+  addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
                        flags, -1, 0);
 
   if (addr != MAP_FAILED) {
--- a/hotspot/src/os/linux/vm/os_linux.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.cpp	Thu May 16 11:47:51 2013 +0100
@@ -119,6 +119,7 @@
 Mutex* os::Linux::_createThread_lock = NULL;
 pthread_t os::Linux::_main_thread;
 int os::Linux::_page_size = -1;
+const int os::Linux::_vm_default_page_size = (8 * K);
 bool os::Linux::_is_floating_stack = false;
 bool os::Linux::_is_NPTL = false;
 bool os::Linux::_supports_fast_thread_cpu_time = false;
@@ -1662,10 +1663,6 @@
   return retval;
 }
 
-const char* os::get_current_directory(char *buf, int buflen) {
-  return getcwd(buf, buflen);
-}
-
 // check if addr is inside libjvm.so
 bool os::address_is_in_vm(address addr) {
   static address libjvm_base_addr;
@@ -2906,9 +2903,10 @@
     flags |= MAP_FIXED;
   }
 
-  // Map uncommitted pages PROT_READ and PROT_WRITE, change access
-  // to PROT_EXEC if executable when we commit the page.
-  addr = (char*)::mmap(requested_addr, bytes, PROT_READ|PROT_WRITE,
+  // Map reserved/uncommitted pages PROT_NONE so we fail early if we
+  // touch an uncommitted page. Otherwise, the read/write might
+  // succeed if we have enough swap space to back the physical page.
+  addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
                        flags, -1, 0);
 
   if (addr != MAP_FAILED) {
@@ -4249,6 +4247,15 @@
   Linux::clock_init();
   initial_time_count = os::elapsed_counter();
   pthread_mutex_init(&dl_mutex, NULL);
+
+  // If the pagesize of the VM is greater than 8K determine the appropriate
+  // number of initial guard pages.  The user can change this with the
+  // command line arguments, if needed.
+  if (vm_page_size() > (int)Linux::vm_default_page_size()) {
+    StackYellowPages = 1;
+    StackRedPages = 1;
+    StackShadowPages = round_to((StackShadowPages*Linux::vm_default_page_size()), vm_page_size()) / vm_page_size();
+  }
 }
 
 // To install functions for atexit system call
@@ -4302,8 +4309,8 @@
   // Add in 2*BytesPerWord times page size to account for VM stack during
   // class initialization depending on 32 or 64 bit VM.
   os::Linux::min_stack_allowed = MAX2(os::Linux::min_stack_allowed,
-            (size_t)(StackYellowPages+StackRedPages+StackShadowPages+
-                    2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::page_size());
+            (size_t)(StackYellowPages+StackRedPages+StackShadowPages) * Linux::page_size() +
+                    (2*BytesPerWord COMPILER2_PRESENT(+1)) * Linux::vm_default_page_size());
 
   size_t threadStackSizeInBytes = ThreadStackSize * K;
   if (threadStackSizeInBytes != 0 &&
--- a/hotspot/src/os/linux/vm/os_linux.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.hpp	Thu May 16 11:47:51 2013 +0100
@@ -70,6 +70,7 @@
   static pthread_t _main_thread;
   static Mutex* _createThread_lock;
   static int _page_size;
+  static const int _vm_default_page_size;
 
   static julong available_memory();
   static julong physical_memory() { return _physical_memory; }
@@ -116,6 +117,8 @@
   static int page_size(void)                                        { return _page_size; }
   static void set_page_size(int val)                                { _page_size = val; }
 
+  static int vm_default_page_size(void)                             { return _vm_default_page_size; }
+
   static address   ucontext_get_pc(ucontext_t* uc);
   static intptr_t* ucontext_get_sp(ucontext_t* uc);
   static intptr_t* ucontext_get_fp(ucontext_t* uc);
--- a/hotspot/src/os/posix/vm/os_posix.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/posix/vm/os_posix.cpp	Thu May 16 11:47:51 2013 +0100
@@ -251,3 +251,11 @@
   return true;
 #endif
 }
+
+const char* os::get_current_directory(char *buf, size_t buflen) {
+  return getcwd(buf, buflen);
+}
+
+FILE* os::open(int fd, const char* mode) {
+  return ::fdopen(fd, mode);
+}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp	Thu May 16 11:47:51 2013 +0100
@@ -824,7 +824,7 @@
       // allocate new buffer and initialize
       info = (Dl_serinfo*)malloc(_info.dls_size);
       if (info == NULL) {
-        vm_exit_out_of_memory(_info.dls_size,
+        vm_exit_out_of_memory(_info.dls_size, OOM_MALLOC_ERROR,
                               "init_system_properties_values info");
       }
       info->dls_size = _info.dls_size;
@@ -866,7 +866,7 @@
       common_path = malloc(bufsize);
       if (common_path == NULL) {
         free(info);
-        vm_exit_out_of_memory(bufsize,
+        vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
                               "init_system_properties_values common_path");
       }
       sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch);
@@ -879,7 +879,7 @@
       if (library_path == NULL) {
         free(info);
         free(common_path);
-        vm_exit_out_of_memory(bufsize,
+        vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
                               "init_system_properties_values library_path");
       }
       library_path[0] = '\0';
@@ -1623,7 +1623,8 @@
   // %%% this is used only in threadLocalStorage.cpp
   if (thr_setspecific((thread_key_t)index, value)) {
     if (errno == ENOMEM) {
-       vm_exit_out_of_memory(SMALLINT, "thr_setspecific: out of swap space");
+       vm_exit_out_of_memory(SMALLINT, OOM_MALLOC_ERROR,
+                             "thr_setspecific: out of swap space");
     } else {
       fatal(err_msg("os::thread_local_storage_at_put: thr_setspecific failed "
                     "(%s)", strerror(errno)));
@@ -1915,10 +1916,6 @@
   return retval;
 }
 
-const char* os::get_current_directory(char *buf, int buflen) {
-  return getcwd(buf, buflen);
-}
-
 // check if addr is inside libjvm.so
 bool os::address_is_in_vm(address addr) {
   static address libjvm_base_addr;
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1221,8 +1221,10 @@
 
 // Needs to be in os specific directory because windows requires another
 // header file <direct.h>
-const char* os::get_current_directory(char *buf, int buflen) {
-  return _getcwd(buf, buflen);
+const char* os::get_current_directory(char *buf, size_t buflen) {
+  int n = static_cast<int>(buflen);
+  if (buflen > INT_MAX)  n = INT_MAX;
+  return _getcwd(buf, n);
 }
 
 //-----------------------------------------------------------
@@ -4098,6 +4100,10 @@
   return ::open(pathbuf, oflag | O_BINARY | O_NOINHERIT, mode);
 }
 
+FILE* os::open(int fd, const char* mode) {
+  return ::_fdopen(fd, mode);
+}
+
 // Is a (classpath) directory empty?
 bool os::dir_is_empty(const char* path) {
   WIN32_FIND_DATA fd;
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp	Thu May 16 11:47:51 2013 +0100
@@ -178,7 +178,7 @@
     // JVM needs to know exact stack location, abort if it fails
     if (rslt != 0) {
       if (rslt == ENOMEM) {
-        vm_exit_out_of_memory(0, "pthread_getattr_np");
+        vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
       } else {
         fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
       }
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp	Thu May 16 11:47:51 2013 +0100
@@ -710,7 +710,7 @@
      // JVM needs to know exact stack location, abort if it fails
      if (rslt != 0) {
        if (rslt == ENOMEM) {
-         vm_exit_out_of_memory(0, "pthread_getattr_np");
+         vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
        } else {
          fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
        }
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Thu May 16 11:47:51 2013 +0100
@@ -313,7 +313,7 @@
   int res = pthread_getattr_np(pthread_self(), &attr);
   if (res != 0) {
     if (res == ENOMEM) {
-      vm_exit_out_of_memory(0, "pthread_getattr_np");
+      vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np");
     }
     else {
       fatal(err_msg("pthread_getattr_np failed with errno = %d", res));
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp	Thu May 16 11:47:51 2013 +0100
@@ -591,7 +591,7 @@
   // on the thread stack, which could get a mapping error when touched.
   address addr = (address) info->si_addr;
   if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
-    vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
+    vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack.");
   }
 
   VMError err(t, sig, pc, info, ucVoid);
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp	Thu May 16 11:47:51 2013 +0100
@@ -745,7 +745,7 @@
   // on the thread stack, which could get a mapping error when touched.
   address addr = (address) info->si_addr;
   if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
-    vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
+    vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack.");
   }
 
   VMError err(t, sig, pc, info, ucVoid);
--- a/hotspot/src/share/vm/adlc/main.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/adlc/main.cpp	Thu May 16 11:47:51 2013 +0100
@@ -213,6 +213,7 @@
   AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._HPP_file._name));
   AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp");
   AD.addInclude(AD._CPP_file, "asm/macroAssembler.inline.hpp");
+  AD.addInclude(AD._CPP_file, "code/compiledIC.hpp");
   AD.addInclude(AD._CPP_file, "code/vmreg.hpp");
   AD.addInclude(AD._CPP_file, "gc_interface/collectedHeap.inline.hpp");
   AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp");
--- a/hotspot/src/share/vm/asm/assembler.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/asm/assembler.cpp	Thu May 16 11:47:51 2013 +0100
@@ -44,7 +44,7 @@
   CodeSection* cs = code->insts();
   cs->clear_mark();   // new assembler kills old mark
   if (cs->start() == NULL)  {
-    vm_exit_out_of_memory(0, err_msg("CodeCache: no room for %s",
+    vm_exit_out_of_memory(0, OOM_MMAP_ERROR, err_msg("CodeCache: no room for %s",
                                      code->name()));
   }
   _code_section = cs;
--- a/hotspot/src/share/vm/ci/ciEnv.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp	Thu May 16 11:47:51 2013 +0100
@@ -483,7 +483,8 @@
     {
       // We have to lock the cpool to keep the oop from being resolved
       // while we are accessing it.
-        MonitorLockerEx ml(cpool->lock());
+      oop cplock = cpool->lock();
+      ObjectLocker ol(cplock, THREAD, cplock != NULL);
       constantTag tag = cpool->tag_at(index);
       if (tag.is_klass()) {
         // The klass has been inserted into the constant pool
@@ -1149,23 +1150,9 @@
   record_method_not_compilable("out of memory");
 }
 
-fileStream* ciEnv::_replay_data_stream = NULL;
-
-void ciEnv::dump_replay_data() {
+void ciEnv::dump_replay_data(outputStream* out) {
   VM_ENTRY_MARK;
   MutexLocker ml(Compile_lock);
-  if (_replay_data_stream == NULL) {
-    _replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
-    if (_replay_data_stream == NULL) {
-      fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
-    }
-  }
-  dump_replay_data(_replay_data_stream);
-}
-
-
-void ciEnv::dump_replay_data(outputStream* out) {
-  ASSERT_IN_VM;
   ResourceMark rm;
 #if INCLUDE_JVMTI
   out->print_cr("JvmtiExport can_access_local_variables %d",     _jvmti_can_access_local_variables);
@@ -1178,13 +1165,15 @@
   for (int i = 0; i < objects->length(); i++) {
     objects->at(i)->dump_replay_data(out);
   }
-  Method* method = task()->method();
-  int entry_bci = task()->osr_bci();
+  CompileTask* task = this->task();
+  Method* method = task->method();
+  int entry_bci = task->osr_bci();
+  int comp_level = task->comp_level();
   // Klass holder = method->method_holder();
-  out->print_cr("compile %s %s %s %d",
+  out->print_cr("compile %s %s %s %d %d",
                 method->klass_name()->as_quoted_ascii(),
                 method->name()->as_quoted_ascii(),
                 method->signature()->as_quoted_ascii(),
-                entry_bci);
+                entry_bci, comp_level);
   out->flush();
 }
--- a/hotspot/src/share/vm/ci/ciEnv.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp	Thu May 16 11:47:51 2013 +0100
@@ -46,8 +46,6 @@
   friend class CompileBroker;
   friend class Dependencies;  // for get_object, during logging
 
-  static fileStream* _replay_data_stream;
-
 private:
   Arena*           _arena;       // Alias for _ciEnv_arena except in init_shared_objects()
   Arena            _ciEnv_arena;
@@ -451,10 +449,6 @@
   // RedefineClasses support
   void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
 
-  // Dump the compilation replay data for this ciEnv to
-  // ReplayDataFile, creating the file if needed.
-  void  dump_replay_data();
-
   // Dump the compilation replay data for the ciEnv to the stream.
   void dump_replay_data(outputStream* out);
 };
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Thu May 16 11:47:51 2013 +0100
@@ -196,7 +196,6 @@
   // Analysis and profiling.
   //
   // Usage note: liveness_at_bci and init_vars should be wrapped in ResourceMarks.
-  bool          uses_monitors() const            { return _uses_monitors; } // this one should go away, it has a misleading name
   bool          has_monitor_bytecodes() const    { return _uses_monitors; }
   bool          has_balanced_monitors();
 
--- a/hotspot/src/share/vm/ci/ciReplay.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/ci/ciReplay.cpp	Thu May 16 11:47:51 2013 +0100
@@ -89,7 +89,7 @@
     loader = Handle(thread, SystemDictionary::java_system_loader());
     stream = fopen(filename, "rt");
     if (stream == NULL) {
-      fprintf(stderr, "Can't open replay file %s\n", filename);
+      fprintf(stderr, "ERROR: Can't open replay file %s\n", filename);
     }
     buffer_length = 32;
     buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
@@ -327,7 +327,6 @@
         if (had_error()) {
           tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
           tty->print_cr("%s", buffer);
-          assert(false, "error");
           return;
         }
         pos = 0;
@@ -370,11 +369,47 @@
     }
   }
 
-  // compile <klass> <name> <signature> <entry_bci>
+  // validation of comp_level
+  bool is_valid_comp_level(int comp_level) {
+    const int msg_len = 256;
+    char* msg = NULL;
+    if (!is_compile(comp_level)) {
+      msg = NEW_RESOURCE_ARRAY(char, msg_len);
+      jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level);
+    } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) {
+      msg = NEW_RESOURCE_ARRAY(char, msg_len);
+      switch (comp_level) {
+        case CompLevel_simple:
+          jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level);
+          break;
+        case CompLevel_full_optimization:
+          jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level);
+          break;
+        default:
+          jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level);
+      }
+    }
+    if (msg != NULL) {
+      report_error(msg);
+      return false;
+    }
+    return true;
+  }
+
+  // compile <klass> <name> <signature> <entry_bci> <comp_level>
   void process_compile(TRAPS) {
     // methodHandle method;
     Method* method = parse_method(CHECK);
     int entry_bci = parse_int("entry_bci");
+    const char* comp_level_label = "comp_level";
+    int comp_level = parse_int(comp_level_label);
+    // old version w/o comp_level
+    if (had_error() && (error_message() == comp_level_label)) {
+      comp_level = CompLevel_full_optimization;
+    }
+    if (!is_valid_comp_level(comp_level)) {
+      return;
+    }
     Klass* k = method->method_holder();
     ((InstanceKlass*)k)->initialize(THREAD);
     if (HAS_PENDING_EXCEPTION) {
@@ -389,12 +424,12 @@
       }
     }
     // Make sure the existence of a prior compile doesn't stop this one
-    nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
+    nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
     if (nm != NULL) {
       nm->make_not_entrant();
     }
     replay_state = this;
-    CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
+    CompileBroker::compile_method(method, entry_bci, comp_level,
                                   methodHandle(), 0, "replay", THREAD);
     replay_state = NULL;
     reset();
@@ -551,7 +586,7 @@
           if (parsed_two_word == i) continue;
 
         default:
-          ShouldNotReachHere();
+          fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value()));
           break;
       }
 
@@ -819,6 +854,11 @@
     ReplaySuppressInitializers = 1;
   }
 
+  if (FLAG_IS_DEFAULT(ReplayDataFile)) {
+    tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt).");
+    return 1;
+  }
+
   // Load and parse the replay data
   CompileReplay rp(ReplayDataFile, THREAD);
   int exit_code = 0;
--- a/hotspot/src/share/vm/classfile/bytecodeAssembler.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/bytecodeAssembler.cpp	Thu May 16 11:47:51 2013 +0100
@@ -75,8 +75,8 @@
     int idx = i + _orig->length();
     switch (entry._tag) {
       case BytecodeCPEntry::UTF8:
+        entry._u.utf8->increment_refcount();
         cp->symbol_at_put(idx, entry._u.utf8);
-        entry._u.utf8->increment_refcount();
         break;
       case BytecodeCPEntry::KLASS:
         cp->unresolved_klass_at_put(
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu May 16 11:47:51 2013 +0100
@@ -2027,7 +2027,6 @@
   u2 method_parameters_length = 0;
   u1* method_parameters_data = NULL;
   bool method_parameters_seen = false;
-  bool method_parameters_four_byte_flags;
   bool parsed_code_attribute = false;
   bool parsed_checked_exceptions_attribute = false;
   bool parsed_stackmap_attribute = false;
@@ -2241,26 +2240,14 @@
       }
       method_parameters_seen = true;
       method_parameters_length = cfs->get_u1_fast();
-      // Track the actual size (note: this is written for clarity; a
-      // decent compiler will CSE and constant-fold this into a single
-      // expression)
-      // Use the attribute length to figure out the size of flags
-      if (method_attribute_length == (method_parameters_length * 6u) + 1u) {
-        method_parameters_four_byte_flags = true;
-      } else if (method_attribute_length == (method_parameters_length * 4u) + 1u) {
-        method_parameters_four_byte_flags = false;
-      } else {
+      if (method_attribute_length != (method_parameters_length * 4u) + 1u) {
         classfile_parse_error(
           "Invalid MethodParameters method attribute length %u in class file",
           method_attribute_length, CHECK_(nullHandle));
       }
       method_parameters_data = cfs->get_u1_buffer();
       cfs->skip_u2_fast(method_parameters_length);
-      if (method_parameters_four_byte_flags) {
-        cfs->skip_u4_fast(method_parameters_length);
-      } else {
-        cfs->skip_u2_fast(method_parameters_length);
-      }
+      cfs->skip_u2_fast(method_parameters_length);
       // ignore this attribute if it cannot be reflected
       if (!SystemDictionary::Parameter_klass_loaded())
         method_parameters_length = 0;
@@ -2423,13 +2410,8 @@
     for (int i = 0; i < method_parameters_length; i++) {
       elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data);
       method_parameters_data += 2;
-      if (method_parameters_four_byte_flags) {
-        elem[i].flags = Bytes::get_Java_u4(method_parameters_data);
-        method_parameters_data += 4;
-      } else {
-        elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
-        method_parameters_data += 2;
-      }
+      elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
+      method_parameters_data += 2;
     }
   }
 
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp	Thu May 16 11:47:51 2013 +0100
@@ -304,7 +304,19 @@
 
   inline void assert_property(bool b, const char* msg, TRAPS) {
 #ifdef ASSERT
-    if (!b) { fatal(msg); }
+    if (!b) {
+      ResourceMark rm(THREAD);
+      fatal(err_msg(msg, _class_name->as_C_string()));
+    }
+#endif
+  }
+
+  inline void assert_property(bool b, const char* msg, int index, TRAPS) {
+#ifdef ASSERT
+    if (!b) {
+      ResourceMark rm(THREAD);
+      fatal(err_msg(msg, index, _class_name->as_C_string()));
+    }
 #endif
   }
 
@@ -312,7 +324,7 @@
     if (_need_verify) {
       guarantee_property(property, msg, index, CHECK);
     } else {
-      assert_property(property, msg, CHECK);
+      assert_property(property, msg, index, CHECK);
     }
   }
 
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1345,9 +1345,10 @@
           tty->print_cr("CompileTheWorld (%d) : %s", _compile_the_world_class_counter, buffer);
           // Preload all classes to get around uncommon traps
           // Iterate over all methods in class
+          int comp_level = CompilationPolicy::policy()->initial_compile_level();
           for (int n = 0; n < k->methods()->length(); n++) {
             methodHandle m (THREAD, k->methods()->at(n));
-            if (CompilationPolicy::can_be_compiled(m)) {
+            if (CompilationPolicy::can_be_compiled(m, comp_level)) {
 
               if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
                 // Give sweeper a chance to keep up with CTW
@@ -1356,7 +1357,7 @@
                 _codecache_sweep_counter = 0;
               }
               // Force compilation
-              CompileBroker::compile_method(m, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(),
+              CompileBroker::compile_method(m, InvocationEntryBci, comp_level,
                                             methodHandle(), 0, "CTW", THREAD);
               if (HAS_PENDING_EXCEPTION) {
                 clear_pending_exception_if_not_oom(CHECK);
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp	Thu May 16 11:47:51 2013 +0100
@@ -53,6 +53,7 @@
 #include "classfile/metadataOnStackMark.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
+#include "memory/gcLocker.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
@@ -65,17 +66,19 @@
 
 ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
 
-ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
+ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
   _class_loader(h_class_loader()),
   _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially
   _metaspace(NULL), _unloading(false), _klasses(NULL),
   _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
-  _next(NULL), _dependencies(),
+  _next(NULL), _dependencies(dependencies),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
     // empty
 }
 
 void ClassLoaderData::init_dependencies(TRAPS) {
+  assert(!Universe::is_fully_initialized(), "should only be called when initializing");
+  assert(is_the_null_class_loader_data(), "should only call this for the null class loader");
   _dependencies.init(CHECK);
 }
 
@@ -277,6 +280,9 @@
 void ClassLoaderData::unload() {
   _unloading = true;
 
+  // Tell serviceability tools these classes are unloading
+  classes_do(InstanceKlass::notify_unload_class);
+
   if (TraceClassLoaderData) {
     ResourceMark rm;
     tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this);
@@ -300,6 +306,9 @@
 
 
 ClassLoaderData::~ClassLoaderData() {
+  // Release C heap structures for all the classes.
+  classes_do(InstanceKlass::release_C_heap_structures);
+
   Metaspace *m = _metaspace;
   if (m != NULL) {
     _metaspace = NULL;
@@ -423,7 +432,7 @@
 // These anonymous class loaders are to contain classes used for JSR292
 ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
   // Add a new class loader data to the graph.
-  return ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL);
+  return ClassLoaderDataGraph::add(loader, true, CHECK_NULL);
 }
 
 const char* ClassLoaderData::loader_name() {
@@ -495,19 +504,22 @@
 ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
 ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
 
-
 // Add a new class loader data node to the list.  Assign the newly created
 // ClassLoaderData into the java/lang/ClassLoader object as a hidden field
-ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) {
-  // Not assigned a class loader data yet.
-  // Create one.
-  ClassLoaderData* *list_head = &_head;
-  ClassLoaderData* next = _head;
+ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous, TRAPS) {
+  // We need to allocate all the oops for the ClassLoaderData before allocating the
+  // actual ClassLoaderData object.
+  ClassLoaderData::Dependencies dependencies(CHECK_NULL);
 
-  bool is_anonymous = (cld_addr == NULL);
-  ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
+  No_Safepoint_Verifier no_safepoints; // we mustn't GC until we've installed the
+                                       // ClassLoaderData in the graph since the CLD
+                                       // contains unhandled oops
 
-  if (cld_addr != NULL) {
+  ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous, dependencies);
+
+
+  if (!is_anonymous) {
+    ClassLoaderData** cld_addr = java_lang_ClassLoader::loader_data_addr(loader());
     // First, Atomically set it
     ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
     if (old != NULL) {
@@ -519,6 +531,9 @@
 
   // We won the race, and therefore the task of adding the data to the list of
   // class loader data
+  ClassLoaderData** list_head = &_head;
+  ClassLoaderData* next = _head;
+
   do {
     cld->set_next(next);
     ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
@@ -531,10 +546,6 @@
                    cld->loader_name());
         tty->print_cr("]");
       }
-      // Create dependencies after the CLD is added to the list.  Otherwise,
-      // the GC GC will not find the CLD and the _class_loader field will
-      // not be updated.
-      cld->init_dependencies(CHECK_NULL);
       return cld;
     }
     next = exchanged;
@@ -665,6 +676,8 @@
     dead->unload();
     data = data->next();
     // Remove from loader list.
+    // This class loader data will no longer be found
+    // in the ClassLoaderDataGraph.
     if (prev != NULL) {
       prev->set_next(data);
     } else {
@@ -686,6 +699,7 @@
     next = purge_me->next();
     delete purge_me;
   }
+  Metaspace::purge();
 }
 
 // CDS support
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp	Thu May 16 11:47:51 2013 +0100
@@ -62,7 +62,7 @@
   // CMS support.
   static ClassLoaderData* _saved_head;
 
-  static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader, TRAPS);
+  static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
  public:
   static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
   static void purge();
@@ -100,6 +100,9 @@
                     Thread* THREAD);
    public:
     Dependencies() : _list_head(NULL) {}
+    Dependencies(TRAPS) : _list_head(NULL) {
+      init(CHECK);
+    }
     void add(Handle dependency, TRAPS);
     void init(TRAPS);
     void oops_do(OopClosure* f);
@@ -150,7 +153,7 @@
   void set_next(ClassLoaderData* next) { _next = next; }
   ClassLoaderData* next() const        { return _next; }
 
-  ClassLoaderData(Handle h_class_loader, bool is_anonymous);
+  ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies);
   ~ClassLoaderData();
 
   void set_metaspace(Metaspace* m) { _metaspace = m; }
@@ -190,7 +193,9 @@
   static void init_null_class_loader_data() {
     assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
     assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");
-    _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false);
+
+    // We explicitly initialize the Dependencies object at a later phase in the initialization
+    _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false, Dependencies());
     ClassLoaderDataGraph::_head = _the_null_class_loader_data;
     assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
     if (DumpSharedSpaces) {
--- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp	Thu May 16 11:47:51 2013 +0100
@@ -43,10 +43,9 @@
   assert(loader() != NULL,"Must be a class loader");
   // Gets the class loader data out of the java/lang/ClassLoader object, if non-null
   // it's already in the loader_data, so no need to add
-  ClassLoaderData** loader_data_addr = java_lang_ClassLoader::loader_data_addr(loader());
-  ClassLoaderData* loader_data_id = *loader_data_addr;
-  if (loader_data_id) {
-     return loader_data_id;
+  ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data(loader());
+  if (loader_data) {
+     return loader_data;
   }
-  return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD);
+  return ClassLoaderDataGraph::add(loader, false, THREAD);
 }
--- a/hotspot/src/share/vm/classfile/dictionary.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp	Thu May 16 11:47:51 2013 +0100
@@ -27,7 +27,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/jvmtiRedefineClassesTrace.hpp"
-#include "services/classLoadingService.hpp"
 #include "utilities/hashtable.inline.hpp"
 
 
@@ -156,19 +155,7 @@
           if (k_def_class_loader_data == loader_data) {
             // This is the defining entry, so the referred class is about
             // to be unloaded.
-            // Notify the debugger and clean up the class.
             class_was_unloaded = true;
-            // notify the debugger
-            if (JvmtiExport::should_post_class_unload()) {
-              JvmtiExport::post_class_unload(ik);
-            }
-
-            // notify ClassLoadingService of class unload
-            ClassLoadingService::notify_class_unloaded(ik);
-
-            // Clean up C heap
-            ik->release_C_heap_structures();
-            ik->constants()->release_C_heap_structures();
           }
           // Also remove this system dictionary entry.
           purge_entry = true;
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu May 16 11:47:51 2013 +0100
@@ -315,14 +315,18 @@
   return string;
 }
 
-jchar* java_lang_String::as_unicode_string(oop java_string, int& length) {
+jchar* java_lang_String::as_unicode_string(oop java_string, int& length, TRAPS) {
   typeArrayOop value  = java_lang_String::value(java_string);
   int          offset = java_lang_String::offset(java_string);
                length = java_lang_String::length(java_string);
 
-  jchar* result = NEW_RESOURCE_ARRAY(jchar, length);
-  for (int index = 0; index < length; index++) {
-    result[index] = value->char_at(index + offset);
+  jchar* result = NEW_RESOURCE_ARRAY_RETURN_NULL(jchar, length);
+  if (result != NULL) {
+    for (int index = 0; index < length; index++) {
+      result[index] = value->char_at(index + offset);
+    }
+  } else {
+    THROW_MSG_0(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string");
   }
   return result;
 }
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Thu May 16 11:47:51 2013 +0100
@@ -153,7 +153,7 @@
   static char*  as_utf8_string(oop java_string, char* buf, int buflen);
   static char*  as_utf8_string(oop java_string, int start, int len);
   static char*  as_platform_dependent_str(Handle java_string, TRAPS);
-  static jchar* as_unicode_string(oop java_string, int& length);
+  static jchar* as_unicode_string(oop java_string, int& length, TRAPS);
   // produce an ascii string with all other values quoted using \u####
   static char*  as_quoted_ascii(oop java_string);
 
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp	Thu May 16 11:47:51 2013 +0100
@@ -735,7 +735,7 @@
   ResourceMark rm(THREAD);
   int length;
   Handle h_string (THREAD, string);
-  jchar* chars = java_lang_String::as_unicode_string(string, length);
+  jchar* chars = java_lang_String::as_unicode_string(string, length, CHECK_NULL);
   oop result = intern(h_string, chars, length, CHECK_NULL);
   return result;
 }
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Thu May 16 11:47:51 2013 +0100
@@ -830,7 +830,7 @@
             Klass *kk;
             {
               MutexLocker mu(SystemDictionary_lock, THREAD);
-              kk = find_class(name, ik->class_loader_data());
+              kk = find_class(d_index, d_hash, name, ik->class_loader_data());
             }
             if (kk != NULL) {
               // No clean up is needed if the shared class has been entered
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Thu May 16 11:47:51 2013 +0100
@@ -517,13 +517,18 @@
   template(sun_management_ManagementFactory,           "sun/management/ManagementFactory")                        \
   template(sun_management_Sensor,                      "sun/management/Sensor")                                   \
   template(sun_management_Agent,                       "sun/management/Agent")                                    \
+  template(sun_management_DiagnosticCommandImpl,       "sun/management/DiagnosticCommandImpl")                    \
   template(sun_management_GarbageCollectorImpl,        "sun/management/GarbageCollectorImpl")                     \
+  template(sun_management_ManagementFactoryHelper,     "sun/management/ManagementFactoryHelper")                  \
+  template(getDiagnosticCommandMBean_name,             "getDiagnosticCommandMBean")                               \
+  template(getDiagnosticCommandMBean_signature,        "()Lcom/sun/management/DiagnosticCommandMBean;")           \
   template(getGcInfoBuilder_name,                      "getGcInfoBuilder")                                        \
   template(getGcInfoBuilder_signature,                 "()Lsun/management/GcInfoBuilder;")                        \
   template(com_sun_management_GcInfo,                  "com/sun/management/GcInfo")                               \
   template(com_sun_management_GcInfo_constructor_signature, "(Lsun/management/GcInfoBuilder;JJJ[Ljava/lang/management/MemoryUsage;[Ljava/lang/management/MemoryUsage;[Ljava/lang/Object;)V") \
   template(createGCNotification_name,                  "createGCNotification")                                    \
   template(createGCNotification_signature,             "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/sun/management/GcInfo;)V") \
+  template(createDiagnosticFrameworkNotification_name, "createDiagnosticFrameworkNotification")                   \
   template(createMemoryPoolMBean_name,                 "createMemoryPoolMBean")                                   \
   template(createMemoryManagerMBean_name,              "createMemoryManagerMBean")                                \
   template(createGarbageCollectorMBean_name,           "createGarbageCollectorMBean")                             \
--- a/hotspot/src/share/vm/code/codeCache.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Thu May 16 11:47:51 2013 +0100
@@ -463,8 +463,10 @@
 }
 #endif //PRODUCT
 
-
-nmethod* CodeCache::find_and_remove_saved_code(Method* m) {
+/**
+ * Remove and return nmethod from the saved code list in order to reanimate it.
+ */
+nmethod* CodeCache::reanimate_saved_code(Method* m) {
   MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
   nmethod* saved = _saved_nmethods;
   nmethod* prev = NULL;
@@ -479,7 +481,7 @@
       saved->set_speculatively_disconnected(false);
       saved->set_saved_nmethod_link(NULL);
       if (PrintMethodFlushing) {
-        saved->print_on(tty, " ### nmethod is reconnected\n");
+        saved->print_on(tty, " ### nmethod is reconnected");
       }
       if (LogCompilation && (xtty != NULL)) {
         ttyLocker ttyl;
@@ -496,6 +498,9 @@
   return NULL;
 }
 
+/**
+ * Remove nmethod from the saved code list in order to discard it permanently
+ */
 void CodeCache::remove_saved_code(nmethod* nm) {
   // For conc swpr this will be called with CodeCache_lock taken by caller
   assert_locked_or_safepoint(CodeCache_lock);
@@ -529,7 +534,7 @@
   nm->set_saved_nmethod_link(_saved_nmethods);
   _saved_nmethods = nm;
   if (PrintMethodFlushing) {
-    nm->print_on(tty, " ### nmethod is speculatively disconnected\n");
+    nm->print_on(tty, " ### nmethod is speculatively disconnected");
   }
   if (LogCompilation && (xtty != NULL)) {
     ttyLocker ttyl;
--- a/hotspot/src/share/vm/code/codeCache.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/codeCache.hpp	Thu May 16 11:47:51 2013 +0100
@@ -57,7 +57,7 @@
   static int _number_of_nmethods_with_dependencies;
   static bool _needs_cache_clean;
   static nmethod* _scavenge_root_nmethods;  // linked via nm->scavenge_root_link()
-  static nmethod* _saved_nmethods;          // linked via nm->saved_nmethod_look()
+  static nmethod* _saved_nmethods;          // Linked list of speculatively disconnected nmethods.
 
   static void verify_if_often() PRODUCT_RETURN;
 
@@ -168,7 +168,7 @@
   static void set_needs_cache_clean(bool v)      { _needs_cache_clean = v;    }
   static void clear_inline_caches();             // clear all inline caches
 
-  static nmethod* find_and_remove_saved_code(Method* m);
+  static nmethod* reanimate_saved_code(Method* m);
   static void remove_saved_code(nmethod* nm);
   static void speculatively_disconnect(nmethod* nm);
 
--- a/hotspot/src/share/vm/code/compiledIC.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/compiledIC.cpp	Thu May 16 11:47:51 2013 +0100
@@ -45,25 +45,6 @@
 // Every time a compiled IC is changed or its type is being accessed,
 // either the CompiledIC_lock must be set or we must be at a safe point.
 
-
-// Release the CompiledICHolder* associated with this call site is there is one.
-void CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site) {
-  // This call site might have become stale so inspect it carefully.
-  NativeCall* call = nativeCall_at(call_site->addr());
-  if (is_icholder_entry(call->destination())) {
-    NativeMovConstReg* value = nativeMovConstReg_at(call_site->cached_value());
-    InlineCacheBuffer::queue_for_release((CompiledICHolder*)value->data());
-  }
-}
-
-
-bool CompiledIC::is_icholder_call_site(virtual_call_Relocation* call_site) {
-  // This call site might have become stale so inspect it carefully.
-  NativeCall* call = nativeCall_at(call_site->addr());
-  return is_icholder_entry(call->destination());
-}
-
-
 //-----------------------------------------------------------------------------
 // Low-level access to an inline cache. Private, since they might not be
 // MT-safe to use.
@@ -488,33 +469,6 @@
   return (cb != NULL && cb->is_adapter_blob());
 }
 
-
-CompiledIC::CompiledIC(nmethod* nm, NativeCall* call)
-  : _ic_call(call)
-{
-  address ic_call = call->instruction_address();
-
-  assert(ic_call != NULL, "ic_call address must be set");
-  assert(nm != NULL, "must pass nmethod");
-  assert(nm->contains(ic_call),   "must be in nmethod");
-
-  // search for the ic_call at the given address
-  RelocIterator iter(nm, ic_call, ic_call+1);
-  bool ret = iter.next();
-  assert(ret == true, "relocInfo must exist at this address");
-  assert(iter.addr() == ic_call, "must find ic_call");
-  if (iter.type() == relocInfo::virtual_call_type) {
-    virtual_call_Relocation* r = iter.virtual_call_reloc();
-    _is_optimized = false;
-    _value = nativeMovConstReg_at(r->cached_value());
-  } else {
-    assert(iter.type() == relocInfo::opt_virtual_call_type, "must be a virtual call");
-    _is_optimized = true;
-    _value = NULL;
-}
-}
-
-
 // ----------------------------------------------------------------------------
 
 void CompiledStaticCall::set_to_clean() {
@@ -549,33 +503,6 @@
   return nm->stub_contains(destination());
 }
 
-
-void CompiledStaticCall::set_to_interpreted(methodHandle callee, address entry) {
-  address stub=find_stub();
-  guarantee(stub != NULL, "stub not found");
-
-  if (TraceICs) {
-    ResourceMark rm;
-    tty->print_cr("CompiledStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s",
-                  instruction_address(),
-                  callee->name_and_sig_as_C_string());
-  }
-
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);   // creation also verifies the object
-  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
-
-  assert(method_holder->data()    == 0           || method_holder->data()    == (intptr_t)callee(), "a) MT-unsafe modification of inline cache");
-  assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, "b) MT-unsafe modification of inline cache");
-
-  // Update stub
-  method_holder->set_data((intptr_t)callee());
-  jump->set_jump_destination(entry);
-
-  // Update jump to call
-  set_destination_mt_safe(stub);
-}
-
-
 void CompiledStaticCall::set(const StaticCallInfo& info) {
   assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
   MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
@@ -618,19 +545,6 @@
   }
 }
 
-
-void CompiledStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
-  // Reset stub
-  address stub = static_stub->addr();
-  assert(stub!=NULL, "stub not found");
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);   // creation also verifies the object
-  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
-  method_holder->set_data(0);
-  jump->set_jump_destination((address)-1);
-}
-
-
 address CompiledStaticCall::find_stub() {
   // Find reloc. information containing this call-site
   RelocIterator iter((nmethod*)NULL, instruction_address());
@@ -668,19 +582,16 @@
           || is_optimized() || is_megamorphic(), "sanity check");
 }
 
-
 void CompiledIC::print() {
   print_compiled_ic();
   tty->cr();
 }
 
-
 void CompiledIC::print_compiled_ic() {
   tty->print("Inline cache at " INTPTR_FORMAT ", calling %s " INTPTR_FORMAT " cached_value " INTPTR_FORMAT,
              instruction_address(), is_call_to_interpreted() ? "interpreted " : "", ic_destination(), is_optimized() ? NULL : cached_value());
 }
 
-
 void CompiledStaticCall::print() {
   tty->print("static call at " INTPTR_FORMAT " -> ", instruction_address());
   if (is_clean()) {
@@ -693,21 +604,4 @@
   tty->cr();
 }
 
-void CompiledStaticCall::verify() {
-  // Verify call
-  NativeCall::verify();
-  if (os::is_MP()) {
-    verify_alignment();
-  }
-
-  // Verify stub
-  address stub = find_stub();
-  assert(stub != NULL, "no stub found for static call");
-  NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);   // creation also verifies the object
-  NativeJump*        jump          = nativeJump_at(method_holder->next_instruction_address());
-
-  // Verify state
-  assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check");
-}
-
-#endif
+#endif // !PRODUCT
--- a/hotspot/src/share/vm/code/compiledIC.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/compiledIC.hpp	Thu May 16 11:47:51 2013 +0100
@@ -304,6 +304,11 @@
   friend CompiledStaticCall* compiledStaticCall_at(address native_call);
   friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site);
 
+  // Code
+  static void emit_to_interp_stub(CodeBuffer &cbuf);
+  static int to_interp_stub_size();
+  static int reloc_to_interp_stub();
+
   // State
   bool is_clean() const;
   bool is_call_to_compiled() const;
--- a/hotspot/src/share/vm/code/stubs.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/stubs.cpp	Thu May 16 11:47:51 2013 +0100
@@ -67,7 +67,7 @@
   intptr_t size = round_to(buffer_size, 2*BytesPerWord);
   BufferBlob* blob = BufferBlob::create(name, size);
   if( blob == NULL) {
-    vm_exit_out_of_memory(size, err_msg("CodeCache: no room for %s", name));
+    vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, err_msg("CodeCache: no room for %s", name));
   }
   _stub_interface  = stub_interface;
   _buffer_size     = blob->content_size();
--- a/hotspot/src/share/vm/code/vtableStubs.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/code/vtableStubs.cpp	Thu May 16 11:47:51 2013 +0100
@@ -60,7 +60,7 @@
     const int bytes = chunk_factor * real_size + pd_code_alignment();
     BufferBlob* blob = BufferBlob::create("vtable chunks", bytes);
     if (blob == NULL) {
-      vm_exit_out_of_memory(bytes, "CodeCache: no room for vtable chunks");
+      vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "CodeCache: no room for vtable chunks");
     }
     _chunk = blob->content_begin();
     _chunk_end = _chunk + bytes;
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp	Thu May 16 11:47:51 2013 +0100
@@ -65,7 +65,7 @@
 HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
   char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool);
 
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name)   \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name)             \
   {                                                                      \
     Symbol* klass_name = (method)->klass_name();                         \
     Symbol* name = (method)->name();                                     \
@@ -77,8 +77,7 @@
       signature->bytes(), signature->utf8_length());                     \
   }
 
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method,                \
-                                        comp_name, success)              \
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)      \
   {                                                                      \
     Symbol* klass_name = (method)->klass_name();                         \
     Symbol* name = (method)->name();                                     \
@@ -92,7 +91,7 @@
 
 #else /* USDT2 */
 
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name)   \
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name)             \
   {                                                                      \
     Symbol* klass_name = (method)->klass_name();                         \
     Symbol* name = (method)->name();                                     \
@@ -104,8 +103,7 @@
       (char *) signature->bytes(), signature->utf8_length());            \
   }
 
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method,                \
-                                        comp_name, success)              \
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)      \
   {                                                                      \
     Symbol* klass_name = (method)->klass_name();                         \
     Symbol* name = (method)->name();                                     \
@@ -120,8 +118,8 @@
 
 #else //  ndef DTRACE_ENABLED
 
-#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler, method, comp_name)
-#define DTRACE_METHOD_COMPILE_END_PROBE(compiler, method, comp_name, success)
+#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name)
+#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)
 
 #endif // ndef DTRACE_ENABLED
 
@@ -1229,7 +1227,7 @@
     if (method->is_not_compilable(comp_level)) return NULL;
 
     if (UseCodeCacheFlushing) {
-      nmethod* saved = CodeCache::find_and_remove_saved_code(method());
+      nmethod* saved = CodeCache::reanimate_saved_code(method());
       if (saved != NULL) {
         method->set_code(method, saved);
         return saved;
@@ -1288,9 +1286,9 @@
     method->jmethod_id();
   }
 
-  // If the compiler is shut off due to code cache flushing or otherwise,
+  // If the compiler is shut off due to code cache getting full
   // fail out now so blocking compiles dont hang the java thread
-  if (!should_compile_new_jobs() || (UseCodeCacheFlushing && CodeCache::needs_flushing())) {
+  if (!should_compile_new_jobs()) {
     CompilationPolicy::policy()->delay_compilation(method());
     return NULL;
   }
@@ -1766,8 +1764,7 @@
     // Save information about this method in case of failure.
     set_last_compile(thread, method, is_osr, task_level);
 
-    DTRACE_METHOD_COMPILE_BEGIN_PROBE(compiler(task_level), method,
-                                      compiler_name(task_level));
+    DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
   }
 
   // Allocate a new set of JNI handles.
@@ -1842,13 +1839,14 @@
         }
       }
     }
+    // simulate crash during compilation
+    assert(task->compile_id() != CICrashAt, "just as planned");
   }
   pop_jni_handle_block();
 
   methodHandle method(thread, task->method());
 
-  DTRACE_METHOD_COMPILE_END_PROBE(compiler(task_level), method,
-                                  compiler_name(task_level), task->is_success());
+  DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
 
   collect_statistics(thread, time, task);
 
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp	Thu May 16 11:47:51 2013 +0100
@@ -193,7 +193,8 @@
      FreeBlockDictionary<FreeChunk>::DictionaryChoice dictionaryChoice) :
   CardGeneration(rs, initial_byte_size, level, ct),
   _dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))),
-  _debug_collection_type(Concurrent_collection_type)
+  _debug_collection_type(Concurrent_collection_type),
+  _did_compact(false)
 {
   HeapWord* bottom = (HeapWord*) _virtual_space.low();
   HeapWord* end    = (HeapWord*) _virtual_space.high();
@@ -917,18 +918,15 @@
     return;
   }
 
-  // Compute some numbers about the state of the heap.
-  const size_t used_after_gc = used();
-  const size_t capacity_after_gc = capacity();
+  // The heap has been compacted but not reset yet.
+  // Any metric such as free() or used() will be incorrect.
 
   CardGeneration::compute_new_size();
 
   // Reset again after a possible resizing
-  cmsSpace()->reset_after_compaction();
-
-  assert(used() == used_after_gc && used_after_gc <= capacity(),
-         err_msg("used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT
-         " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity()));
+  if (did_compact()) {
+    cmsSpace()->reset_after_compaction();
+  }
 }
 
 void ConcurrentMarkSweepGeneration::compute_new_size_free_list() {
@@ -1578,6 +1576,8 @@
   return false;
 }
 
+void CMSCollector::set_did_compact(bool v) { _cmsGen->set_did_compact(v); }
+
 // Clear _expansion_cause fields of constituent generations
 void CMSCollector::clear_expansion_cause() {
   _cmsGen->clear_expansion_cause();
@@ -1675,7 +1675,6 @@
   }
   acquire_control_and_collect(full, clear_all_soft_refs);
   _full_gcs_since_conc_gc++;
-
 }
 
 void CMSCollector::request_full_gc(unsigned int full_gc_count) {
@@ -1857,6 +1856,7 @@
     }
   }
 
+  set_did_compact(should_compact);
   if (should_compact) {
     // If the collection is being acquired from the background
     // collector, there may be references on the discovered
@@ -2444,8 +2444,7 @@
         // initial marking in checkpointRootsInitialWork has been completed
         if (VerifyDuringGC &&
             GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
-          gclog_or_tty->print("Verify before initial mark: ");
-          Universe::verify();
+          Universe::verify("Verify before initial mark: ");
         }
         {
           bool res = markFromRoots(false);
@@ -2456,8 +2455,7 @@
       case FinalMarking:
         if (VerifyDuringGC &&
             GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
-          gclog_or_tty->print("Verify before re-mark: ");
-          Universe::verify();
+          Universe::verify("Verify before re-mark: ");
         }
         checkpointRootsFinal(false, clear_all_soft_refs,
                              init_mark_was_synchronous);
@@ -2468,8 +2466,7 @@
         // final marking in checkpointRootsFinal has been completed
         if (VerifyDuringGC &&
             GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
-          gclog_or_tty->print("Verify before sweep: ");
-          Universe::verify();
+          Universe::verify("Verify before sweep: ");
         }
         sweep(false);
         assert(_collectorState == Resizing, "Incorrect state");
@@ -2484,8 +2481,7 @@
         // The heap has been resized.
         if (VerifyDuringGC &&
             GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
-          gclog_or_tty->print("Verify before reset: ");
-          Universe::verify();
+          Universe::verify("Verify before reset: ");
         }
         reset(false);
         assert(_collectorState == Idling, "Collector state should "
@@ -2722,6 +2718,7 @@
     Chunk::clean_chunk_pool();
   }
 
+  set_did_compact(false);
   _between_prologue_and_epilogue = false;  // ready for next cycle
 }
 
@@ -2853,8 +2850,8 @@
   bool failed() { return _failed; }
 };
 
-bool CMSCollector::verify_after_remark() {
-  gclog_or_tty->print(" [Verifying CMS Marking... ");
+bool CMSCollector::verify_after_remark(bool silent) {
+  if (!silent) gclog_or_tty->print(" [Verifying CMS Marking... ");
   MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag);
   static bool init = false;
 
@@ -2915,7 +2912,7 @@
     warning("Unrecognized value %d for CMSRemarkVerifyVariant",
             CMSRemarkVerifyVariant);
   }
-  gclog_or_tty->print(" done] ");
+  if (!silent) gclog_or_tty->print(" done] ");
   return true;
 }
 
@@ -3426,8 +3423,9 @@
 void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) {
   assert_locked_or_safepoint(Heap_lock);
   assert_lock_strong(freelistLock());
-  // XXX Fix when compaction is implemented.
-  warning("Shrinking of CMS not yet implemented");
+  if (PrintGCDetails && Verbose) {
+    warning("Shrinking of CMS not yet implemented");
+  }
   return;
 }
 
@@ -6010,26 +6008,23 @@
                                         &cmsDrainMarkingStackClosure,
                                         NULL);
     }
-    verify_work_stacks_empty();
-  }
+  }
+
+  // This is the point where the entire marking should have completed.
+  verify_work_stacks_empty();
 
   if (should_unload_classes()) {
     {
       TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty);
 
-      // Follow SystemDictionary roots and unload classes
+      // Unload classes and purge the SystemDictionary.
       bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure);
 
-      // Follow CodeCache roots and unload any methods marked for unloading
+      // Unload nmethods.
       CodeCache::do_unloading(&_is_alive_closure, purged_class);
 
-      cmsDrainMarkingStackClosure.do_void();
-      verify_work_stacks_empty();
-
-      // Update subklass/sibling/implementor links in KlassKlass descendants
+      // Prune dead klasses from subklass/sibling/implementor lists.
       Klass::clean_weak_klass_links(&_is_alive_closure);
-      // Nothing should have been pushed onto the working stacks.
-      verify_work_stacks_empty();
     }
 
     {
@@ -6043,11 +6038,10 @@
   // Need to check if we really scanned the StringTable.
   if ((roots_scanning_options() & SharedHeap::SO_Strings) == 0) {
     TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty);
-    // Now clean up stale oops in StringTable
+    // Delete entries for dead interned strings.
     StringTable::unlink(&_is_alive_closure);
   }
 
-  verify_work_stacks_empty();
   // Restore any preserved marks as a result of mark stack or
   // work queue overflow
   restore_preserved_marks_if_any();  // done single-threaded for now
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp	Thu May 16 11:47:51 2013 +0100
@@ -604,6 +604,8 @@
   ConcurrentMarkSweepPolicy* _collector_policy;
   ConcurrentMarkSweepPolicy* collector_policy() { return _collector_policy; }
 
+  void set_did_compact(bool v);
+
   // XXX Move these to CMSStats ??? FIX ME !!!
   elapsedTimer _inter_sweep_timer;   // time between sweeps
   elapsedTimer _intra_sweep_timer;   // time _in_ sweeps
@@ -990,7 +992,7 @@
 
   // debugging
   void verify();
-  bool verify_after_remark();
+  bool verify_after_remark(bool silent = VerifySilently);
   void verify_ok_to_terminate() const PRODUCT_RETURN;
   void verify_work_stacks_empty() const PRODUCT_RETURN;
   void verify_overflow_empty() const PRODUCT_RETURN;
@@ -1081,6 +1083,10 @@
 
   CollectionTypes _debug_collection_type;
 
+  // True if a compactiing collection was done.
+  bool _did_compact;
+  bool did_compact() { return _did_compact; }
+
   // Fraction of current occupancy at which to start a CMS collection which
   // will collect this generation (at least).
   double _initiating_occupancy;
@@ -1121,6 +1127,8 @@
   // Adaptive size policy
   CMSAdaptiveSizePolicy* size_policy();
 
+  void set_did_compact(bool v) { _did_compact = v; }
+
   bool refs_discovery_is_atomic() const { return false; }
   bool refs_discovery_is_mt()     const {
     // Note: CMS does MT-discovery during the parallel-remark
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,40 +26,12 @@
 #include "gc_implementation/g1/concurrentG1Refine.hpp"
 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
-#include "gc_implementation/g1/g1CollectorPolicy.hpp"
-#include "gc_implementation/g1/g1GCPhaseTimes.hpp"
-#include "gc_implementation/g1/g1RemSet.hpp"
-#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
-#include "memory/space.inline.hpp"
-#include "runtime/atomic.hpp"
-#include "runtime/java.hpp"
-#include "utilities/copy.hpp"
-
-// Possible sizes for the card counts cache: odd primes that roughly double in size.
-// (See jvmtiTagMap.cpp).
-
-#define MAX_SIZE ((size_t) -1)
+#include "gc_implementation/g1/g1HotCardCache.hpp"
 
-size_t ConcurrentG1Refine::_cc_cache_sizes[] = {
-          16381,    32771,    76831,    150001,   307261,
-         614563,  1228891,  2457733,   4915219,  9830479,
-       19660831, 39321619, 78643219, 157286461,  MAX_SIZE
-  };
-
-ConcurrentG1Refine::ConcurrentG1Refine() :
-  _card_counts(NULL), _card_epochs(NULL),
-  _n_card_counts(0), _max_cards(0), _max_n_card_counts(0),
-  _cache_size_index(0), _expand_card_counts(false),
-  _hot_cache(NULL),
-  _def_use_cache(false), _use_cache(false),
-  // We initialize the epochs of the array to 0. By initializing
-  // _n_periods to 1 and not 0 we automatically invalidate all the
-  // entries on the array. Otherwise we might accidentally think that
-  // we claimed a card that was in fact never set (see CR7033292).
-  _n_periods(1),
-  _threads(NULL), _n_threads(0)
+ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) :
+  _threads(NULL), _n_threads(0),
+  _hot_card_cache(g1h)
 {
-
   // Ergomonically select initial concurrent refinement parameters
   if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
     FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, MAX2<int>(ParallelGCThreads, 1));
@@ -75,13 +47,17 @@
     FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2);
   }
   set_red_zone(MAX2<int>(G1ConcRefinementRedZone, yellow_zone()));
+
   _n_worker_threads = thread_num();
   // We need one extra thread to do the young gen rset size sampling.
   _n_threads = _n_worker_threads + 1;
+
   reset_threshold_step();
 
   _threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads, mtGC);
+
   int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids();
+
   ConcurrentG1RefineThread *next = NULL;
   for (int i = _n_threads - 1; i >= 0; i--) {
     ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i);
@@ -100,74 +76,8 @@
   }
 }
 
-int ConcurrentG1Refine::thread_num() {
-  return MAX2<int>((G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads : ParallelGCThreads, 1);
-}
-
 void ConcurrentG1Refine::init() {
-  if (G1ConcRSLogCacheSize > 0) {
-    _g1h = G1CollectedHeap::heap();
-
-    _max_cards = _g1h->max_capacity() >> CardTableModRefBS::card_shift;
-    _max_n_card_counts = _max_cards * G1MaxHotCardCountSizePercent / 100;
-
-    size_t max_card_num = ((size_t)1 << (sizeof(unsigned)*BitsPerByte-1)) - 1;
-    guarantee(_max_cards < max_card_num, "card_num representation");
-
-    // We need _n_card_counts to be less than _max_n_card_counts here
-    // so that the expansion call (below) actually allocates the
-    // _counts and _epochs arrays.
-    assert(_n_card_counts == 0, "pre-condition");
-    assert(_max_n_card_counts > 0, "pre-condition");
-
-    // Find the index into cache size array that is of a size that's
-    // large enough to hold desired_sz.
-    size_t desired_sz = _max_cards / InitialCacheFraction;
-    int desired_sz_index = 0;
-    while (_cc_cache_sizes[desired_sz_index] < desired_sz) {
-      desired_sz_index += 1;
-      assert(desired_sz_index <  MAX_CC_CACHE_INDEX, "invariant");
-    }
-    assert(desired_sz_index <  MAX_CC_CACHE_INDEX, "invariant");
-
-    // If the desired_sz value is between two sizes then
-    // _cc_cache_sizes[desired_sz_index-1] < desired_sz <= _cc_cache_sizes[desired_sz_index]
-    // we will start with the lower size in the optimistic expectation that
-    // we will not need to expand up. Note desired_sz_index could also be 0.
-    if (desired_sz_index > 0 &&
-        _cc_cache_sizes[desired_sz_index] > desired_sz) {
-      desired_sz_index -= 1;
-    }
-
-    if (!expand_card_count_cache(desired_sz_index)) {
-      // Allocation was unsuccessful - exit
-      vm_exit_during_initialization("Could not reserve enough space for card count cache");
-    }
-    assert(_n_card_counts > 0, "post-condition");
-    assert(_cache_size_index == desired_sz_index, "post-condition");
-
-    Copy::fill_to_bytes(&_card_counts[0],
-                        _n_card_counts * sizeof(CardCountCacheEntry));
-    Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry));
-
-    ModRefBarrierSet* bs = _g1h->mr_bs();
-    guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition");
-    _ct_bs = (CardTableModRefBS*)bs;
-    _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start());
-
-    _def_use_cache = true;
-    _use_cache = true;
-    _hot_cache_size = (1 << G1ConcRSLogCacheSize);
-    _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size, mtGC);
-    _n_hot = 0;
-    _hot_cache_idx = 0;
-
-    // For refining the cards in the hot cache in parallel
-    int n_workers = (ParallelGCThreads > 0 ?
-                        _g1h->workers()->total_workers() : 1);
-    _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers);
-    _hot_cache_par_claimed_idx = 0;
-  }
+  _hot_card_cache.initialize();
 }
 
 void ConcurrentG1Refine::stop() {
@@ -188,17 +98,6 @@
 }
 
 ConcurrentG1Refine::~ConcurrentG1Refine() {
-  if (G1ConcRSLogCacheSize > 0) {
-    // Please see the comment in allocate_card_count_cache
-    // for why we call os::malloc() and os::free() directly.
-    assert(_card_counts != NULL, "Logic");
-    os::free(_card_counts, mtGC);
-    assert(_card_epochs != NULL, "Logic");
-    os::free(_card_epochs, mtGC);
-
-    assert(_hot_cache != NULL, "Logic");
-    FREE_C_HEAP_ARRAY(jbyte*, _hot_cache, mtGC);
-  }
   if (_threads != NULL) {
     for (int i = 0; i < _n_threads; i++) {
       delete _threads[i];
@@ -215,317 +114,10 @@
   }
 }
 
-bool ConcurrentG1Refine::is_young_card(jbyte* card_ptr) {
-  HeapWord* start = _ct_bs->addr_for(card_ptr);
-  HeapRegion* r = _g1h->heap_region_containing(start);
-  if (r != NULL && r->is_young()) {
-    return true;
-  }
-  // This card is not associated with a heap region
-  // so can't be young.
-  return false;
-}
-
-jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* defer) {
-  unsigned new_card_num = ptr_2_card_num(card_ptr);
-  unsigned bucket = hash(new_card_num);
-  assert(0 <= bucket && bucket < _n_card_counts, "Bounds");
-
-  CardCountCacheEntry* count_ptr = &_card_counts[bucket];
-  CardEpochCacheEntry* epoch_ptr = &_card_epochs[bucket];
-
-  // We have to construct a new entry if we haven't updated the counts
-  // during the current period, or if the count was updated for a
-  // different card number.
-  unsigned int new_epoch = (unsigned int) _n_periods;
-  julong new_epoch_entry = make_epoch_entry(new_card_num, new_epoch);
-
-  while (true) {
-    // Fetch the previous epoch value
-    julong prev_epoch_entry = epoch_ptr->_value;
-    julong cas_res;
-
-    if (extract_epoch(prev_epoch_entry) != new_epoch) {
-      // This entry has not yet been updated during this period.
-      // Note: we update the epoch value atomically to ensure
-      // that there is only one winner that updates the cached
-      // card_ptr value even though all the refine threads share
-      // the same epoch value.
-
-      cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry,
-                                         (volatile jlong*)&epoch_ptr->_value,
-                                         (jlong) prev_epoch_entry);
-
-      if (cas_res == prev_epoch_entry) {
-        // We have successfully won the race to update the
-        // epoch and card_num value. Make it look like the
-        // count and eviction count were previously cleared.
-        count_ptr->_count = 1;
-        count_ptr->_evict_count = 0;
-        *count = 0;
-        // We can defer the processing of card_ptr
-        *defer = true;
-        return card_ptr;
-      }
-      // We did not win the race to update the epoch field, so some other
-      // thread must have done it. The value that gets returned by CAS
-      // should be the new epoch value.
-      assert(extract_epoch(cas_res) == new_epoch, "unexpected epoch");
-      // We could 'continue' here or just re-read the previous epoch value
-      prev_epoch_entry = epoch_ptr->_value;
-    }
-
-    // The epoch entry for card_ptr has been updated during this period.
-    unsigned old_card_num = extract_card_num(prev_epoch_entry);
-
-    // The card count that will be returned to caller
-    *count = count_ptr->_count;
-
-    // Are we updating the count for the same card?
-    if (new_card_num == old_card_num) {
-      // Same card - just update the count. We could have more than one
-      // thread racing to update count for the current card. It should be
-      // OK not to use a CAS as the only penalty should be some missed
-      // increments of the count which delays identifying the card as "hot".
-
-      if (*count < max_jubyte) count_ptr->_count++;
-      // We can defer the processing of card_ptr
-      *defer = true;
-      return card_ptr;
-    }
-
-    // Different card - evict old card info
-    if (count_ptr->_evict_count < max_jubyte) count_ptr->_evict_count++;
-    if (count_ptr->_evict_count > G1CardCountCacheExpandThreshold) {
-      // Trigger a resize the next time we clear
-      _expand_card_counts = true;
-    }
-
-    cas_res = (julong) Atomic::cmpxchg((jlong) new_epoch_entry,
-                                       (volatile jlong*)&epoch_ptr->_value,
-                                       (jlong) prev_epoch_entry);
-
-    if (cas_res == prev_epoch_entry) {
-      // We successfully updated the card num value in the epoch entry
-      count_ptr->_count = 0; // initialize counter for new card num
-      jbyte* old_card_ptr = card_num_2_ptr(old_card_num);
-
-      // Even though the region containg the card at old_card_num was not
-      // in the young list when old_card_num was recorded in the epoch
-      // cache it could have been added to the free list and subsequently
-      // added to the young list in the intervening time. See CR 6817995.
-      // We do not deal with this case here - it will be handled in
-      // HeapRegion::oops_on_card_seq_iterate_careful after it has been
-      // determined that the region containing the card has been allocated
-      // to, and it's safe to check the young type of the region.
-
-      // We do not want to defer processing of card_ptr in this case
-      // (we need to refine old_card_ptr and card_ptr)
-      *defer = false;
-      return old_card_ptr;
-    }
-    // Someone else beat us - try again.
-  }
-}
-
-jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
-  int count;
-  jbyte* cached_ptr = add_card_count(card_ptr, &count, defer);
-  assert(cached_ptr != NULL, "bad cached card ptr");
-
-  // We've just inserted a card pointer into the card count cache
-  // and got back the card that we just inserted or (evicted) the
-  // previous contents of that count slot.
-
-  // The card we got back could be in a young region. When the
-  // returned card (if evicted) was originally inserted, we had
-  // determined that its containing region was not young. However
-  // it is possible for the region to be freed during a cleanup
-  // pause, then reallocated and tagged as young which will result
-  // in the returned card residing in a young region.
-  //
-  // We do not deal with this case here - the change from non-young
-  // to young could be observed at any time - it will be handled in
-  // HeapRegion::oops_on_card_seq_iterate_careful after it has been
-  // determined that the region containing the card has been allocated
-  // to.
-
-  // The card pointer we obtained from card count cache is not hot
-  // so do not store it in the cache; return it for immediate
-  // refining.
-  if (count < G1ConcRSHotCardLimit) {
-    return cached_ptr;
-  }
-
-  // Otherwise, the pointer we got from the _card_counts cache is hot.
-  jbyte* res = NULL;
-  MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
-  if (_n_hot == _hot_cache_size) {
-    res = _hot_cache[_hot_cache_idx];
-    _n_hot--;
-  }
-  // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx.
-  _hot_cache[_hot_cache_idx] = cached_ptr;
-  _hot_cache_idx++;
-  if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0;
-  _n_hot++;
-
-  // The card obtained from the hot card cache could be in a young
-  // region. See above on how this can happen.
-
-  return res;
-}
-
-void ConcurrentG1Refine::clean_up_cache(int worker_i,
-                                        G1RemSet* g1rs,
-                                        DirtyCardQueue* into_cset_dcq) {
-  assert(!use_cache(), "cache should be disabled");
-  int start_idx;
-
-  while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once
-    int end_idx = start_idx + _hot_cache_par_chunk_size;
-
-    if (start_idx ==
-        Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) {
-      // The current worker has successfully claimed the chunk [start_idx..end_idx)
-      end_idx = MIN2(end_idx, _n_hot);
-      for (int i = start_idx; i < end_idx; i++) {
-        jbyte* entry = _hot_cache[i];
-        if (entry != NULL) {
-          if (g1rs->concurrentRefineOneCard(entry, worker_i, true)) {
-            // 'entry' contains references that point into the current
-            // collection set. We need to record 'entry' in the DCQS
-            // that's used for that purpose.
-            //
-            // The only time we care about recording cards that contain
-            // references that point into the collection set is during
-            // RSet updating while within an evacuation pause.
-            // In this case worker_i should be the id of a GC worker thread
-            assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
-            assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "incorrect worker id");
-            into_cset_dcq->enqueue(entry);
-          }
-        }
-      }
-    }
-  }
-}
-
-// The arrays used to hold the card counts and the epochs must have
-// a 1:1 correspondence. Hence they are allocated and freed together
-// Returns true if the allocations of both the counts and epochs
-// were successful; false otherwise.
-bool ConcurrentG1Refine::allocate_card_count_cache(size_t n,
-                                                   CardCountCacheEntry** counts,
-                                                   CardEpochCacheEntry** epochs) {
-  // We call the allocation/free routines directly for the counts
-  // and epochs arrays. The NEW_C_HEAP_ARRAY/FREE_C_HEAP_ARRAY
-  // macros call AllocateHeap and FreeHeap respectively.
-  // AllocateHeap will call vm_exit_out_of_memory in the event
-  // of an allocation failure and abort the JVM. With the
-  // _counts/epochs arrays we only need to abort the JVM if the
-  // initial allocation of these arrays fails.
-  //
-  // Additionally AllocateHeap/FreeHeap do some tracing of
-  // allocate/free calls so calling one without calling the
-  // other can cause inconsistencies in the tracing. So we
-  // call neither.
-
-  assert(*counts == NULL, "out param");
-  assert(*epochs == NULL, "out param");
-
-  size_t counts_size = n * sizeof(CardCountCacheEntry);
-  size_t epochs_size = n * sizeof(CardEpochCacheEntry);
-
-  *counts = (CardCountCacheEntry*) os::malloc(counts_size, mtGC);
-  if (*counts == NULL) {
-    // allocation was unsuccessful
-    return false;
-  }
-
-  *epochs = (CardEpochCacheEntry*) os::malloc(epochs_size, mtGC);
-  if (*epochs == NULL) {
-    // allocation was unsuccessful - free counts array
-    assert(*counts != NULL, "must be");
-    os::free(*counts, mtGC);
-    *counts = NULL;
-    return false;
-  }
-
-  // We successfully allocated both counts and epochs
-  return true;
-}
-
-// Returns true if the card counts/epochs cache was
-// successfully expanded; false otherwise.
-bool ConcurrentG1Refine::expand_card_count_cache(int cache_size_idx) {
-  // Can we expand the card count and epoch tables?
-  if (_n_card_counts < _max_n_card_counts) {
-    assert(cache_size_idx >= 0 && cache_size_idx  < MAX_CC_CACHE_INDEX, "oob");
-
-    size_t cache_size = _cc_cache_sizes[cache_size_idx];
-    // Make sure we don't go bigger than we will ever need
-    cache_size = MIN2(cache_size, _max_n_card_counts);
-
-    // Should we expand the card count and card epoch tables?
-    if (cache_size > _n_card_counts) {
-      // We have been asked to allocate new, larger, arrays for
-      // the card counts and the epochs. Attempt the allocation
-      // of both before we free the existing arrays in case
-      // the allocation is unsuccessful...
-      CardCountCacheEntry* counts = NULL;
-      CardEpochCacheEntry* epochs = NULL;
-
-      if (allocate_card_count_cache(cache_size, &counts, &epochs)) {
-        // Allocation was successful.
-        // We can just free the old arrays; we're
-        // not interested in preserving the contents
-        if (_card_counts != NULL) os::free(_card_counts, mtGC);
-        if (_card_epochs != NULL) os::free(_card_epochs, mtGC);
-
-        // Cache the size of the arrays and the index that got us there.
-        _n_card_counts = cache_size;
-        _cache_size_index = cache_size_idx;
-
-        _card_counts = counts;
-        _card_epochs = epochs;
-
-        // We successfully allocated/expanded the caches.
-        return true;
-      }
-    }
-  }
-
-  // We did not successfully expand the caches.
-  return false;
-}
-
-void ConcurrentG1Refine::clear_and_record_card_counts() {
-  if (G1ConcRSLogCacheSize == 0) {
-    return;
-  }
-
-  double start = os::elapsedTime();
-
-  if (_expand_card_counts) {
-    int new_idx = _cache_size_index + 1;
-
-    if (expand_card_count_cache(new_idx)) {
-      // Allocation was successful and  _n_card_counts has
-      // been updated to the new size. We only need to clear
-      // the epochs so we don't read a bogus epoch value
-      // when inserting a card into the hot card cache.
-      Copy::fill_to_bytes(&_card_epochs[0], _n_card_counts * sizeof(CardEpochCacheEntry));
-    }
-    _expand_card_counts = false;
-  }
-
-  int this_epoch = (int) _n_periods;
-  assert((this_epoch+1) <= max_jint, "to many periods");
-  // Update epoch
-  _n_periods++;
-  double cc_clear_time_ms = (os::elapsedTime() - start) * 1000;
-  _g1h->g1_policy()->phase_times()->record_cc_clear_time_ms(cc_clear_time_ms);
+int ConcurrentG1Refine::thread_num() {
+  int n_threads = (G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads
+                                                : ParallelGCThreads;
+  return MAX2<int>(n_threads, 1);
 }
 
 void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const {
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,15 @@
 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP
 #define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP
 
+#include "gc_implementation/g1/g1HotCardCache.hpp"
 #include "memory/allocation.hpp"
-#include "memory/cardTableModRefBS.hpp"
 #include "runtime/thread.hpp"
 #include "utilities/globalDefinitions.hpp"
 
 // Forward decl
 class ConcurrentG1RefineThread;
+class G1CollectedHeap;
+class G1HotCardCache;
 class G1RemSet;
 
 class ConcurrentG1Refine: public CHeapObj<mtGC> {
@@ -61,141 +63,14 @@
 
   int _thread_threshold_step;
 
+  // We delay the refinement of 'hot' cards using the hot card cache.
+  G1HotCardCache _hot_card_cache;
+
   // Reset the threshold step value based of the current zone boundaries.
   void reset_threshold_step();
 
-  // The cache for card refinement.
-  bool   _use_cache;
-  bool   _def_use_cache;
-
-  size_t _n_periods;    // Used as clearing epoch
-
-  // An evicting cache of the number of times each card
-  // is accessed. Reduces, but does not eliminate, the amount
-  // of duplicated processing of dirty cards.
-
-  enum SomePrivateConstants {
-    epoch_bits           = 32,
-    card_num_shift       = epoch_bits,
-    epoch_mask           = AllBits,
-    card_num_mask        = AllBits,
-
-    // The initial cache size is approximately this fraction
-    // of a maximal cache (i.e. the size needed for all cards
-    // in the heap)
-    InitialCacheFraction = 512
-  };
-
-  const static julong card_num_mask_in_place =
-                        (julong) card_num_mask << card_num_shift;
-
-  typedef struct {
-    julong _value;      // |  card_num   |  epoch   |
-  } CardEpochCacheEntry;
-
-  julong make_epoch_entry(unsigned int card_num, unsigned int epoch) {
-    assert(0 <= card_num && card_num < _max_cards, "Bounds");
-    assert(0 <= epoch && epoch <= _n_periods, "must be");
-
-    return ((julong) card_num << card_num_shift) | epoch;
-  }
-
-  unsigned int extract_epoch(julong v) {
-    return (v & epoch_mask);
-  }
-
-  unsigned int extract_card_num(julong v) {
-    return (v & card_num_mask_in_place) >> card_num_shift;
-  }
-
-  typedef struct {
-    unsigned char _count;
-    unsigned char _evict_count;
-  } CardCountCacheEntry;
-
-  CardCountCacheEntry* _card_counts;
-  CardEpochCacheEntry* _card_epochs;
-
-  // The current number of buckets in the card count cache
-  size_t _n_card_counts;
-
-  // The number of cards for the entire reserved heap
-  size_t _max_cards;
-
-  // The max number of buckets for the card counts and epochs caches.
-  // This is the maximum that the counts and epochs will grow to.
-  // It is specified as a fraction or percentage of _max_cards using
-  // G1MaxHotCardCountSizePercent.
-  size_t _max_n_card_counts;
-
-  // Possible sizes of the cache: odd primes that roughly double in size.
-  // (See jvmtiTagMap.cpp).
-  enum {
-    MAX_CC_CACHE_INDEX = 15    // maximum index into the cache size array.
-  };
-
-  static size_t _cc_cache_sizes[MAX_CC_CACHE_INDEX];
-
-  // The index in _cc_cache_sizes corresponding to the size of
-  // _card_counts.
-  int _cache_size_index;
-
-  bool _expand_card_counts;
-
-  const jbyte* _ct_bot;
-
-  jbyte**      _hot_cache;
-  int          _hot_cache_size;
-  int          _n_hot;
-  int          _hot_cache_idx;
-
-  int          _hot_cache_par_chunk_size;
-  volatile int _hot_cache_par_claimed_idx;
-
-  // Needed to workaround 6817995
-  CardTableModRefBS* _ct_bs;
-  G1CollectedHeap*   _g1h;
-
-  // Helper routine for expand_card_count_cache().
-  // The arrays used to hold the card counts and the epochs must have
-  // a 1:1 correspondence. Hence they are allocated and freed together.
-  // Returns true if the allocations of both the counts and epochs
-  // were successful; false otherwise.
-  bool allocate_card_count_cache(size_t n,
-                                 CardCountCacheEntry** counts,
-                                 CardEpochCacheEntry** epochs);
-
-  // Expands the arrays that hold the card counts and epochs
-  // to the cache size at index. Returns true if the expansion/
-  // allocation was successful; false otherwise.
-  bool expand_card_count_cache(int index);
-
-  // hash a given key (index of card_ptr) with the specified size
-  static unsigned int hash(size_t key, size_t size) {
-    return (unsigned int) (key % size);
-  }
-
-  // hash a given key (index of card_ptr)
-  unsigned int hash(size_t key) {
-    return hash(key, _n_card_counts);
-  }
-
-  unsigned int ptr_2_card_num(jbyte* card_ptr) {
-    return (unsigned int) (card_ptr - _ct_bot);
-  }
-
-  jbyte* card_num_2_ptr(unsigned int card_num) {
-    return (jbyte*) (_ct_bot + card_num);
-  }
-
-  // Returns the count of this card after incrementing it.
-  jbyte* add_card_count(jbyte* card_ptr, int* count, bool* defer);
-
-  // Returns true if this card is in a young region
-  bool is_young_card(jbyte* card_ptr);
-
  public:
-  ConcurrentG1Refine();
+  ConcurrentG1Refine(G1CollectedHeap* g1h);
   ~ConcurrentG1Refine();
 
   void init(); // Accomplish some initialization that has to wait.
@@ -206,34 +81,6 @@
   // Iterate over the conc refine threads
   void threads_do(ThreadClosure *tc);
 
-  // If this is the first entry for the slot, writes into the cache and
-  // returns NULL.  If it causes an eviction, returns the evicted pointer.
-  // Otherwise, its a cache hit, and returns NULL.
-  jbyte* cache_insert(jbyte* card_ptr, bool* defer);
-
-  // Process the cached entries.
-  void clean_up_cache(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq);
-
-  // Set up for parallel processing of the cards in the hot cache
-  void clear_hot_cache_claimed_index() {
-    _hot_cache_par_claimed_idx = 0;
-  }
-
-  // Discard entries in the hot cache.
-  void clear_hot_cache() {
-    _hot_cache_idx = 0; _n_hot = 0;
-  }
-
-  bool hot_cache_is_empty() { return _n_hot == 0; }
-
-  bool use_cache() { return _use_cache; }
-  void set_use_cache(bool b) {
-    if (b) _use_cache = _def_use_cache;
-    else   _use_cache = false;
-  }
-
-  void clear_and_record_card_counts();
-
   static int thread_num();
 
   void print_worker_threads_on(outputStream* st) const;
@@ -250,6 +97,8 @@
   int worker_thread_num() const { return _n_worker_threads; }
 
   int thread_threshold_step() const { return _thread_threshold_step; }
+
+  G1HotCardCache* hot_card_cache() { return &_hot_card_cache; }
 };
 
 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1273,10 +1273,9 @@
 
   if (VerifyDuringGC) {
     HandleMark hm;  // handle scope
-    gclog_or_tty->print(" VerifyDuringGC:(before)");
     Universe::heap()->prepare_for_verify();
-    Universe::verify(/* silent */ false,
-                     /* option */ VerifyOption_G1UsePrevMarking);
+    Universe::verify(VerifyOption_G1UsePrevMarking,
+                     " VerifyDuringGC:(before)");
   }
 
   G1CollectorPolicy* g1p = g1h->g1_policy();
@@ -1300,10 +1299,9 @@
     // Verify the heap w.r.t. the previous marking bitmap.
     if (VerifyDuringGC) {
       HandleMark hm;  // handle scope
-      gclog_or_tty->print(" VerifyDuringGC:(overflow)");
       Universe::heap()->prepare_for_verify();
-      Universe::verify(/* silent */ false,
-                       /* option */ VerifyOption_G1UsePrevMarking);
+      Universe::verify(VerifyOption_G1UsePrevMarking,
+                       " VerifyDuringGC:(overflow)");
     }
 
     // Clear the marking state because we will be restarting
@@ -1323,10 +1321,9 @@
 
     if (VerifyDuringGC) {
       HandleMark hm;  // handle scope
-      gclog_or_tty->print(" VerifyDuringGC:(after)");
       Universe::heap()->prepare_for_verify();
-      Universe::verify(/* silent */ false,
-                       /* option */ VerifyOption_G1UseNextMarking);
+      Universe::verify(VerifyOption_G1UseNextMarking,
+                       " VerifyDuringGC:(after)");
     }
     assert(!restart_for_overflow(), "sanity");
     // Completely reset the marking state since marking completed
@@ -1972,10 +1969,9 @@
 
   if (VerifyDuringGC) {
     HandleMark hm;  // handle scope
-    gclog_or_tty->print(" VerifyDuringGC:(before)");
     Universe::heap()->prepare_for_verify();
-    Universe::verify(/* silent */ false,
-                     /* option */ VerifyOption_G1UsePrevMarking);
+    Universe::verify(VerifyOption_G1UsePrevMarking,
+                     " VerifyDuringGC:(before)");
   }
 
   G1CollectorPolicy* g1p = G1CollectedHeap::heap()->g1_policy();
@@ -2127,10 +2123,9 @@
 
   if (VerifyDuringGC) {
     HandleMark hm;  // handle scope
-    gclog_or_tty->print(" VerifyDuringGC:(after)");
     Universe::heap()->prepare_for_verify();
-    Universe::verify(/* silent */ false,
-                     /* option */ VerifyOption_G1UsePrevMarking);
+    Universe::verify(VerifyOption_G1UsePrevMarking,
+                     " VerifyDuringGC:(after)");
   }
 
   g1h->verify_region_sets_optional();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.cpp	Thu May 16 11:47:51 2013 +0100
@@ -77,7 +77,7 @@
     assert(delta > 0, "just checking");
     if (!_vs.expand_by(delta)) {
       // Do better than this for Merlin
-      vm_exit_out_of_memory(delta, "offset table expansion");
+      vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
     }
     assert(_vs.high() == high + delta, "invalid expansion");
     // Initialization of the contents is left to the
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.cpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/g1CardCounts.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1CollectorPolicy.hpp"
+#include "gc_implementation/g1/g1GCPhaseTimes.hpp"
+#include "memory/cardTableModRefBS.hpp"
+#include "services/memTracker.hpp"
+#include "utilities/copy.hpp"
+
+void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) {
+  if (has_count_table()) {
+    check_card_num(from_card_num,
+                   err_msg("from card num out of range: "SIZE_FORMAT, from_card_num));
+    assert(from_card_num < to_card_num,
+           err_msg("Wrong order? from: " SIZE_FORMAT ", to: "SIZE_FORMAT,
+                   from_card_num, to_card_num));
+    assert(to_card_num <= _committed_max_card_num,
+           err_msg("to card num out of range: "
+                   "to: "SIZE_FORMAT ", "
+                   "max: "SIZE_FORMAT,
+                   to_card_num, _committed_max_card_num));
+
+    to_card_num = MIN2(_committed_max_card_num, to_card_num);
+
+    Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num));
+  }
+}
+
+G1CardCounts::G1CardCounts(G1CollectedHeap *g1h):
+  _g1h(g1h), _card_counts(NULL),
+  _reserved_max_card_num(0), _committed_max_card_num(0),
+  _committed_size(0) {}
+
+void G1CardCounts::initialize() {
+  assert(_g1h->max_capacity() > 0, "initialization order");
+  assert(_g1h->capacity() == 0, "initialization order");
+
+  if (G1ConcRSHotCardLimit > 0) {
+    // The max value we can store in the counts table is
+    // max_jubyte. Guarantee the value of the hot
+    // threshold limit is no more than this.
+    guarantee(G1ConcRSHotCardLimit <= max_jubyte, "sanity");
+
+    ModRefBarrierSet* bs = _g1h->mr_bs();
+    guarantee(bs->is_a(BarrierSet::CardTableModRef), "Precondition");
+    _ct_bs = (CardTableModRefBS*)bs;
+    _ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start());
+
+    // Allocate/Reserve the counts table
+    size_t reserved_bytes = _g1h->max_capacity();
+    _reserved_max_card_num = reserved_bytes >> CardTableModRefBS::card_shift;
+
+    size_t reserved_size = _reserved_max_card_num * sizeof(jbyte);
+    ReservedSpace rs(ReservedSpace::allocation_align_size_up(reserved_size));
+    if (!rs.is_reserved()) {
+      warning("Could not reserve enough space for the card counts table");
+      guarantee(!has_reserved_count_table(), "should be NULL");
+      return;
+    }
+
+    MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
+
+    _card_counts_storage.initialize(rs, 0);
+    _card_counts = (jubyte*) _card_counts_storage.low();
+  }
+}
+
+void G1CardCounts::resize(size_t heap_capacity) {
+  // Expand the card counts table to handle a heap with the given capacity.
+
+  if (!has_reserved_count_table()) {
+    // Don't expand if we failed to reserve the card counts table.
+    return;
+  }
+
+  assert(_committed_size ==
+         ReservedSpace::allocation_align_size_up(_committed_size),
+         err_msg("Unaligned? committed_size: " SIZE_FORMAT, _committed_size));
+
+  // Verify that the committed space for the card counts
+  // matches our committed max card num.
+  size_t prev_committed_size = _committed_size;
+  size_t prev_committed_card_num = prev_committed_size / sizeof(jbyte);
+  assert(prev_committed_card_num == _committed_max_card_num,
+         err_msg("Card mismatch: "
+                 "prev: " SIZE_FORMAT ", "
+                 "committed: "SIZE_FORMAT,
+                 prev_committed_card_num, _committed_max_card_num));
+
+  size_t new_size = (heap_capacity >> CardTableModRefBS::card_shift) * sizeof(jbyte);
+  size_t new_committed_size = ReservedSpace::allocation_align_size_up(new_size);
+  size_t new_committed_card_num =
+                MIN2(_reserved_max_card_num, new_committed_size / sizeof(jbyte));
+
+  if (_committed_max_card_num < new_committed_card_num) {
+    // we need to expand the backing store for the card counts
+    size_t expand_size = new_committed_size - prev_committed_size;
+
+    if (!_card_counts_storage.expand_by(expand_size)) {
+      warning("Card counts table backing store commit failure");
+      return;
+    }
+    assert(_card_counts_storage.committed_size() == new_committed_size,
+           "expansion commit failure");
+
+    _committed_size = new_committed_size;
+    _committed_max_card_num = new_committed_card_num;
+
+    clear_range(prev_committed_card_num, _committed_max_card_num);
+  }
+}
+
+uint G1CardCounts::add_card_count(jbyte* card_ptr) {
+  // Returns the number of times the card has been refined.
+  // If we failed to reserve/commit the counts table, return 0.
+  // If card_ptr is beyond the committed end of the counts table,
+  // return 0.
+  // Otherwise return the actual count.
+  // Unless G1ConcRSHotCardLimit has been set appropriately,
+  // returning 0 will result in the card being considered
+  // cold and will be refined immediately.
+  uint count = 0;
+  if (has_count_table()) {
+    size_t card_num = ptr_2_card_num(card_ptr);
+    if (card_num < _committed_max_card_num) {
+      count = (uint) _card_counts[card_num];
+      if (count < G1ConcRSHotCardLimit) {
+        _card_counts[card_num] += 1;
+      }
+      assert(_card_counts[card_num] <= G1ConcRSHotCardLimit,
+             err_msg("Refinement count overflow? "
+                     "new count: "UINT32_FORMAT,
+                     (uint) _card_counts[card_num]));
+    }
+  }
+  return count;
+}
+
+bool G1CardCounts::is_hot(uint count) {
+  return (count >= G1ConcRSHotCardLimit);
+}
+
+void G1CardCounts::clear_region(HeapRegion* hr) {
+  assert(!hr->isHumongous(), "Should have been cleared");
+  if (has_count_table()) {
+    HeapWord* bottom = hr->bottom();
+
+    // We use the last address in hr as hr could be the
+    // last region in the heap. In which case trying to find
+    // the card for hr->end() will be an OOB accesss to the
+    // card table.
+    HeapWord* last = hr->end() - 1;
+    assert(_g1h->g1_committed().contains(last),
+           err_msg("last not in committed: "
+                   "last: " PTR_FORMAT ", "
+                   "committed: [" PTR_FORMAT ", " PTR_FORMAT ")",
+                   last,
+                   _g1h->g1_committed().start(),
+                   _g1h->g1_committed().end()));
+
+    const jbyte* from_card_ptr = _ct_bs->byte_for_const(bottom);
+    const jbyte* last_card_ptr = _ct_bs->byte_for_const(last);
+
+#ifdef ASSERT
+    HeapWord* start_addr = _ct_bs->addr_for(from_card_ptr);
+    assert(start_addr == hr->bottom(), "alignment");
+    HeapWord* last_addr = _ct_bs->addr_for(last_card_ptr);
+    assert((last_addr + CardTableModRefBS::card_size_in_words) == hr->end(), "alignment");
+#endif // ASSERT
+
+    // Clear the counts for the (exclusive) card range.
+    size_t from_card_num = ptr_2_card_num(from_card_ptr);
+    size_t to_card_num = ptr_2_card_num(last_card_ptr) + 1;
+    clear_range(from_card_num, to_card_num);
+  }
+}
+
+void G1CardCounts::clear_all() {
+  assert(SafepointSynchronize::is_at_safepoint(), "don't call this otherwise");
+  clear_range((size_t)0, _committed_max_card_num);
+}
+
+G1CardCounts::~G1CardCounts() {
+  if (has_reserved_count_table()) {
+    _card_counts_storage.release();
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CardCounts.hpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/virtualspace.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class CardTableModRefBS;
+class G1CollectedHeap;
+class HeapRegion;
+
+// Table to track the number of times a card has been refined. Once
+// a card has been refined a certain number of times, it is
+// considered 'hot' and its refinement is delayed by inserting the
+// card into the hot card cache. The card will then be refined when
+// it is evicted from the hot card cache, or when the hot card cache
+// is 'drained' during the next evacuation pause.
+
+class G1CardCounts: public CHeapObj<mtGC> {
+  G1CollectedHeap* _g1h;
+
+  // The table of counts
+  jubyte* _card_counts;
+
+  // Max capacity of the reserved space for the counts table
+  size_t _reserved_max_card_num;
+
+  // Max capacity of the committed space for the counts table
+  size_t _committed_max_card_num;
+
+  // Size of committed space for the counts table
+  size_t _committed_size;
+
+  // CardTable bottom.
+  const jbyte* _ct_bot;
+
+  // Barrier set
+  CardTableModRefBS* _ct_bs;
+
+  // The virtual memory backing the counts table
+  VirtualSpace _card_counts_storage;
+
+  // Returns true if the card counts table has been reserved.
+  bool has_reserved_count_table() { return _card_counts != NULL; }
+
+  // Returns true if the card counts table has been reserved and committed.
+  bool has_count_table() {
+    return has_reserved_count_table() && _committed_max_card_num > 0;
+  }
+
+  void check_card_num(size_t card_num, const char* msg) {
+    assert(card_num >= 0 && card_num < _committed_max_card_num, msg);
+  }
+
+  size_t ptr_2_card_num(const jbyte* card_ptr) {
+    assert(card_ptr >= _ct_bot,
+           err_msg("Inavalied card pointer: "
+                   "card_ptr: " PTR_FORMAT ", "
+                   "_ct_bot: " PTR_FORMAT,
+                   card_ptr, _ct_bot));
+    size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte));
+    check_card_num(card_num,
+                   err_msg("card pointer out of range: " PTR_FORMAT, card_ptr));
+    return card_num;
+  }
+
+  jbyte* card_num_2_ptr(size_t card_num) {
+    check_card_num(card_num,
+                   err_msg("card num out of range: "SIZE_FORMAT, card_num));
+    return (jbyte*) (_ct_bot + card_num);
+  }
+
+  // Clear the counts table for the given (exclusive) index range.
+  void clear_range(size_t from_card_num, size_t to_card_num);
+
+ public:
+  G1CardCounts(G1CollectedHeap* g1h);
+  ~G1CardCounts();
+
+  void initialize();
+
+  // Resize the committed space for the card counts table in
+  // response to a resize of the committed space for the heap.
+  void resize(size_t heap_capacity);
+
+  // Increments the refinement count for the given card.
+  // Returns the pre-increment count value.
+  uint add_card_count(jbyte* card_ptr);
+
+  // Returns true if the given count is high enough to be considered
+  // 'hot'; false otherwise.
+  bool is_hot(uint count);
+
+  // Clears the card counts for the cards spanned by the region
+  void clear_region(HeapRegion* hr);
+
+  // Clear the entire card counts table during GC.
+  // Updates the policy stats with the duration.
+  void clear_all();
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CARDCOUNTS_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Thu May 16 11:47:51 2013 +0100
@@ -96,7 +96,7 @@
     _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true)
   {}
   bool do_card_ptr(jbyte* card_ptr, int worker_i) {
-    bool oops_into_cset = _g1rs->concurrentRefineOneCard(card_ptr, worker_i, false);
+    bool oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false);
     // This path is executed by the concurrent refine or mutator threads,
     // concurrently, and so we do not care if card_ptr contains references
     // that point into the collection set.
@@ -1271,9 +1271,8 @@
   if (guard && total_collections() >= VerifyGCStartAt) {
     double verify_start = os::elapsedTime();
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(msg);
     prepare_for_verify();
-    Universe::verify(false /* silent */, VerifyOption_G1UsePrevMarking);
+    Universe::verify(VerifyOption_G1UsePrevMarking, msg);
     verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
   }
 
@@ -1304,7 +1303,7 @@
 
   print_heap_before_gc();
 
-  size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+  size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
 
   HRSPhaseSetter x(HRSPhaseFullGC);
   verify_region_sets_optional();
@@ -1425,6 +1424,7 @@
 
       // Delete metaspaces for unloaded class loaders and clean up loader_data graph
       ClassLoaderDataGraph::purge();
+    MetaspaceAux::verify_metrics();
 
       // Note: since we've just done a full GC, concurrent
       // marking is no longer active. Therefore we need not
@@ -1452,9 +1452,10 @@
         _hr_printer.end_gc(true /* full */, (size_t) total_collections());
       }
 
-      if (_cg1r->use_cache()) {
-        _cg1r->clear_and_record_card_counts();
-        _cg1r->clear_hot_cache();
+      G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
+      if (hot_card_cache->use_cache()) {
+        hot_card_cache->reset_card_counts();
+        hot_card_cache->reset_hot_cache();
       }
 
       // Rebuild remembered sets of all regions.
@@ -1767,6 +1768,8 @@
   Universe::heap()->barrier_set()->resize_covered_region(_g1_committed);
   // Tell the BOT about the update.
   _bot_shared->resize(_g1_committed.word_size());
+  // Tell the hot card cache about the update
+  _cg1r->hot_card_cache()->resize_card_counts(capacity());
 }
 
 bool G1CollectedHeap::expand(size_t expand_bytes) {
@@ -1831,7 +1834,7 @@
     if (G1ExitOnExpansionFailure &&
         _g1_storage.uncommitted_size() >= aligned_expand_bytes) {
       // We had head room...
-      vm_exit_out_of_memory(aligned_expand_bytes, "G1 heap expansion");
+      vm_exit_out_of_memory(aligned_expand_bytes, OOM_MMAP_ERROR, "G1 heap expansion");
     }
   }
   return successful;
@@ -1843,33 +1846,32 @@
     ReservedSpace::page_align_size_down(shrink_bytes);
   aligned_shrink_bytes = align_size_down(aligned_shrink_bytes,
                                          HeapRegion::GrainBytes);
-  uint num_regions_deleted = 0;
-  MemRegion mr = _hrs.shrink_by(aligned_shrink_bytes, &num_regions_deleted);
+  uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes);
+
+  uint num_regions_removed = _hrs.shrink_by(num_regions_to_remove);
   HeapWord* old_end = (HeapWord*) _g1_storage.high();
-  assert(mr.end() == old_end, "post-condition");
+  size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes;
 
   ergo_verbose3(ErgoHeapSizing,
                 "shrink the heap",
                 ergo_format_byte("requested shrinking amount")
                 ergo_format_byte("aligned shrinking amount")
                 ergo_format_byte("attempted shrinking amount"),
-                shrink_bytes, aligned_shrink_bytes, mr.byte_size());
-  if (mr.byte_size() > 0) {
+                shrink_bytes, aligned_shrink_bytes, shrunk_bytes);
+  if (num_regions_removed > 0) {
+    _g1_storage.shrink_by(shrunk_bytes);
+    HeapWord* new_end = (HeapWord*) _g1_storage.high();
+
     if (_hr_printer.is_active()) {
-      HeapWord* curr = mr.end();
-      while (curr > mr.start()) {
+      HeapWord* curr = old_end;
+      while (curr > new_end) {
         HeapWord* curr_end = curr;
         curr -= HeapRegion::GrainWords;
         _hr_printer.uncommit(curr, curr_end);
       }
-      assert(curr == mr.start(), "post-condition");
     }
 
-    _g1_storage.shrink_by(mr.byte_size());
-    HeapWord* new_end = (HeapWord*) _g1_storage.high();
-    assert(mr.start() == new_end, "post-condition");
-
-    _expansion_regions += num_regions_deleted;
+    _expansion_regions += num_regions_removed;
     update_committed_space(old_end, new_end);
     HeapRegionRemSet::shrink_heap(n_regions());
     g1_policy()->record_new_heap_size(n_regions());
@@ -1955,13 +1957,6 @@
   int n_rem_sets = HeapRegionRemSet::num_par_rem_sets();
   assert(n_rem_sets > 0, "Invariant.");
 
-  HeapRegionRemSetIterator** iter_arr =
-    NEW_C_HEAP_ARRAY(HeapRegionRemSetIterator*, n_queues, mtGC);
-  for (int i = 0; i < n_queues; i++) {
-    iter_arr[i] = new HeapRegionRemSetIterator();
-  }
-  _rem_set_iterator = iter_arr;
-
   _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
   _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC);
 
@@ -2007,7 +2002,7 @@
   Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap");
   Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
 
-  _cg1r = new ConcurrentG1Refine();
+  _cg1r = new ConcurrentG1Refine(this);
 
   // Reserve the maximum.
 
@@ -2068,6 +2063,9 @@
                   (HeapWord*) _g1_reserved.end(),
                   _expansion_regions);
 
+  // Do later initialization work for concurrent refinement.
+  _cg1r->init();
+
   // 6843694 - ensure that the maximum region index can fit
   // in the remembered set structures.
   const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1;
@@ -2085,20 +2083,20 @@
 
   _g1h = this;
 
-   _in_cset_fast_test_length = max_regions();
-   _in_cset_fast_test_base =
+  _in_cset_fast_test_length = max_regions();
+  _in_cset_fast_test_base =
                    NEW_C_HEAP_ARRAY(bool, (size_t) _in_cset_fast_test_length, mtGC);
 
-   // We're biasing _in_cset_fast_test to avoid subtracting the
-   // beginning of the heap every time we want to index; basically
-   // it's the same with what we do with the card table.
-   _in_cset_fast_test = _in_cset_fast_test_base -
+  // We're biasing _in_cset_fast_test to avoid subtracting the
+  // beginning of the heap every time we want to index; basically
+  // it's the same with what we do with the card table.
+  _in_cset_fast_test = _in_cset_fast_test_base -
                ((uintx) _g1_reserved.start() >> HeapRegion::LogOfHRGrainBytes);
 
-   // Clear the _cset_fast_test bitmap in anticipation of adding
-   // regions to the incremental collection set for the first
-   // evacuation pause.
-   clear_cset_fast_test();
+  // Clear the _cset_fast_test bitmap in anticipation of adding
+  // regions to the incremental collection set for the first
+  // evacuation pause.
+  clear_cset_fast_test();
 
   // Create the ConcurrentMark data structure and thread.
   // (Must do this late, so that "max_regions" is defined.)
@@ -2160,9 +2158,6 @@
   // counts and that mechanism.
   SpecializationStats::clear();
 
-  // Do later initialization work for concurrent refinement.
-  _cg1r->init();
-
   // Here we allocate the dummy full region that is required by the
   // G1AllocRegion class. If we don't pass an address in the reserved
   // space here, lots of asserts fire.
@@ -2321,7 +2316,8 @@
                                                  bool concurrent,
                                                  int worker_i) {
   // Clean cards in the hot card cache
-  concurrent_g1_refine()->clean_up_cache(worker_i, g1_rem_set(), into_cset_dcq);
+  G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
+  hot_card_cache->drain(worker_i, g1_rem_set(), into_cset_dcq);
 
   DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
   int n_completed_buffers = 0;
@@ -3614,7 +3610,7 @@
   uint array_length = g1_policy()->young_cset_region_length();
   _surviving_young_words = NEW_C_HEAP_ARRAY(size_t, (size_t) array_length, mtGC);
   if (_surviving_young_words == NULL) {
-    vm_exit_out_of_memory(sizeof(size_t) * array_length,
+    vm_exit_out_of_memory(sizeof(size_t) * array_length, OOM_MALLOC_ERROR,
                           "Not enough space for young surv words summary.");
   }
   memset(_surviving_young_words, 0, (size_t) array_length * sizeof(size_t));
@@ -4397,7 +4393,7 @@
                       PADDING_ELEM_NUM;
   _surviving_young_words_base = NEW_C_HEAP_ARRAY(size_t, array_length, mtGC);
   if (_surviving_young_words_base == NULL)
-    vm_exit_out_of_memory(array_length * sizeof(size_t),
+    vm_exit_out_of_memory(array_length * sizeof(size_t), OOM_MALLOC_ERROR,
                           "Not enough space for young surv histo.");
   _surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM;
   memset(_surviving_young_words, 0, (size_t) real_length * sizeof(size_t));
@@ -5079,10 +5075,9 @@
 }
 
 void
-G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure,
-                                       OopClosure* non_root_closure) {
+G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure) {
   CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false);
-  SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure);
+  SharedHeap::process_weak_roots(root_closure, &roots_in_blobs);
 }
 
 // Weak Reference Processing support
@@ -5612,8 +5607,11 @@
   NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();)
 
   g1_rem_set()->prepare_for_oops_into_collection_set_do();
-  concurrent_g1_refine()->set_use_cache(false);
-  concurrent_g1_refine()->clear_hot_cache_claimed_index();
+
+  // Disable the hot card cache.
+  G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
+  hot_card_cache->reset_hot_cache_claimed_index();
+  hot_card_cache->set_use_cache(false);
 
   uint n_workers;
   if (G1CollectedHeap::use_parallel_gc_threads()) {
@@ -5695,8 +5693,11 @@
   release_gc_alloc_regions(n_workers);
   g1_rem_set()->cleanup_after_oops_into_collection_set_do();
 
-  concurrent_g1_refine()->clear_hot_cache();
-  concurrent_g1_refine()->set_use_cache(true);
+  // Reset and re-enable the hot card cache.
+  // Note the counts for the cards in the regions in the
+  // collection set are reset when the collection set is freed.
+  hot_card_cache->reset_hot_cache();
+  hot_card_cache->set_use_cache(true);
 
   finalize_for_evac_failure();
 
@@ -5758,6 +5759,12 @@
   assert(!hr->is_empty(), "the region should not be empty");
   assert(free_list != NULL, "pre-condition");
 
+  // Clear the card counts for this region.
+  // Note: we only need to do this if the region is not young
+  // (since we don't refine cards in young regions).
+  if (!hr->is_young()) {
+    _cg1r->hot_card_cache()->reset_card_counts(hr);
+  }
   *pre_used += hr->used();
   hr->hr_clear(par, true /* clear_space */);
   free_list->add_as_head(hr);
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Thu May 16 11:47:51 2013 +0100
@@ -786,9 +786,6 @@
   // concurrently after the collection.
   DirtyCardQueueSet _dirty_card_queue_set;
 
-  // The Heap Region Rem Set Iterator.
-  HeapRegionRemSetIterator** _rem_set_iterator;
-
   // The closure used to refine a single card.
   RefineCardTableEntryClosure* _refine_cte_cl;
 
@@ -827,8 +824,7 @@
   // Apply "blk" to all the weak roots of the system.  These include
   // JNI weak roots, the code cache, system dictionary, symbol table,
   // string table, and referents of reachable weak refs.
-  void g1_process_weak_roots(OopClosure* root_closure,
-                             OopClosure* non_root_closure);
+  void g1_process_weak_roots(OopClosure* root_closure);
 
   // Frees a non-humongous region by initializing its contents and
   // adding it to the free list that's passed as a parameter (this is
@@ -1114,15 +1110,6 @@
   G1RemSet* g1_rem_set() const { return _g1_rem_set; }
   ModRefBarrierSet* mr_bs() const { return _mr_bs; }
 
-  // The rem set iterator.
-  HeapRegionRemSetIterator* rem_set_iterator(int i) {
-    return _rem_set_iterator[i];
-  }
-
-  HeapRegionRemSetIterator* rem_set_iterator() {
-    return _rem_set_iterator[0];
-  }
-
   unsigned get_gc_time_stamp() {
     return _gc_time_stamp;
   }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp	Thu May 16 11:47:51 2013 +0100
@@ -309,7 +309,8 @@
 
 void G1CollectorPolicy::initialize_flags() {
   set_min_alignment(HeapRegion::GrainBytes);
-  set_max_alignment(GenRemSet::max_alignment_constraint(rem_set_name()));
+  size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name());
+  set_max_alignment(MAX2(card_table_alignment, min_alignment()));
   if (SurvivorRatio < 1) {
     vm_exit_during_initialization("Invalid survivor ratio specified");
   }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -155,11 +155,6 @@
 
 G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
   _max_gc_threads(max_gc_threads),
-  _min_clear_cc_time_ms(-1.0),
-  _max_clear_cc_time_ms(-1.0),
-  _cur_clear_cc_time_ms(0.0),
-  _cum_clear_cc_time_ms(0.0),
-  _num_cc_clears(0L),
   _last_gc_worker_start_times_ms(_max_gc_threads, "%.1lf", false),
   _last_ext_root_scan_times_ms(_max_gc_threads, "%.1lf"),
   _last_satb_filtering_times_ms(_max_gc_threads, "%.1lf"),
@@ -212,11 +207,11 @@
     _last_gc_worker_times_ms.set(i, worker_time);
 
     double worker_known_time = _last_ext_root_scan_times_ms.get(i) +
-      _last_satb_filtering_times_ms.get(i) +
-      _last_update_rs_times_ms.get(i) +
-      _last_scan_rs_times_ms.get(i) +
-      _last_obj_copy_times_ms.get(i) +
-      _last_termination_times_ms.get(i);
+                               _last_satb_filtering_times_ms.get(i) +
+                               _last_update_rs_times_ms.get(i) +
+                               _last_scan_rs_times_ms.get(i) +
+                               _last_obj_copy_times_ms.get(i) +
+                               _last_termination_times_ms.get(i);
 
     double worker_other_time = worker_time - worker_known_time;
     _last_gc_worker_other_times_ms.set(i, worker_other_time);
@@ -285,15 +280,6 @@
   }
   print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
   print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
-  if (Verbose && G1Log::finest()) {
-    print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms);
-    print_stats(1, "Cum Clear CC", _cum_clear_cc_time_ms);
-    print_stats(1, "Min Clear CC", _min_clear_cc_time_ms);
-    print_stats(1, "Max Clear CC", _max_clear_cc_time_ms);
-    if (_num_cc_clears > 0) {
-      print_stats(1, "Avg Clear CC", _cum_clear_cc_time_ms / ((double)_num_cc_clears));
-    }
-  }
   double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms();
   print_stats(1, "Other", misc_time_ms);
   if (_cur_verify_before_time_ms > 0.0) {
@@ -311,19 +297,3 @@
     print_stats(2, "Verify After", _cur_verify_after_time_ms);
   }
 }
-
-void G1GCPhaseTimes::record_cc_clear_time_ms(double ms) {
-  if (!(Verbose && G1Log::finest())) {
-    return;
-  }
-
-  if (_min_clear_cc_time_ms < 0.0 || ms <= _min_clear_cc_time_ms) {
-    _min_clear_cc_time_ms = ms;
-  }
-  if (_max_clear_cc_time_ms < 0.0 || ms >= _max_clear_cc_time_ms) {
-    _max_clear_cc_time_ms = ms;
-  }
-  _cur_clear_cc_time_ms = ms;
-  _cum_clear_cc_time_ms += ms;
-  _num_cc_clears++;
-}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -133,13 +133,6 @@
   double _cur_ref_proc_time_ms;
   double _cur_ref_enq_time_ms;
 
-  // Card Table Count Cache stats
-  double _min_clear_cc_time_ms;         // min
-  double _max_clear_cc_time_ms;         // max
-  double _cur_clear_cc_time_ms;         // clearing time during current pause
-  double _cum_clear_cc_time_ms;         // cummulative clearing time
-  jlong  _num_cc_clears;                // number of times the card count cache has been cleared
-
   double _cur_collection_start_sec;
   double _root_region_scan_wait_time_ms;
 
@@ -227,8 +220,6 @@
     _root_region_scan_wait_time_ms = time_ms;
   }
 
-  void record_cc_clear_time_ms(double ms);
-
   void record_young_free_cset_time_ms(double time_ms) {
     _recorded_young_free_cset_time_ms = time_ms;
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/dirtyCardQueue.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1HotCardCache.hpp"
+#include "gc_implementation/g1/g1RemSet.hpp"
+#include "gc_implementation/g1/heapRegion.hpp"
+#include "runtime/atomic.hpp"
+
+G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h):
+  _g1h(g1h), _hot_cache(NULL), _use_cache(false), _card_counts(g1h) {}
+
+void G1HotCardCache::initialize() {
+  if (default_use_cache()) {
+    _use_cache = true;
+
+    _hot_cache_size = (1 << G1ConcRSLogCacheSize);
+    _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size, mtGC);
+
+    _n_hot = 0;
+    _hot_cache_idx = 0;
+
+    // For refining the cards in the hot cache in parallel
+    int n_workers = (ParallelGCThreads > 0 ?
+                        _g1h->workers()->total_workers() : 1);
+    _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers);
+    _hot_cache_par_claimed_idx = 0;
+
+    _card_counts.initialize();
+  }
+}
+
+G1HotCardCache::~G1HotCardCache() {
+  if (default_use_cache()) {
+    assert(_hot_cache != NULL, "Logic");
+    FREE_C_HEAP_ARRAY(jbyte*, _hot_cache, mtGC);
+  }
+}
+
+jbyte* G1HotCardCache::insert(jbyte* card_ptr) {
+  uint count = _card_counts.add_card_count(card_ptr);
+  if (!_card_counts.is_hot(count)) {
+    // The card is not hot so do not store it in the cache;
+    // return it for immediate refining.
+    return card_ptr;
+  }
+
+  // Otherwise, the card is hot.
+  jbyte* res = NULL;
+  MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
+  if (_n_hot == _hot_cache_size) {
+    res = _hot_cache[_hot_cache_idx];
+    _n_hot--;
+  }
+
+  // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx.
+  _hot_cache[_hot_cache_idx] = card_ptr;
+  _hot_cache_idx++;
+
+  if (_hot_cache_idx == _hot_cache_size) {
+    // Wrap around
+    _hot_cache_idx = 0;
+  }
+  _n_hot++;
+
+  return res;
+}
+
+void G1HotCardCache::drain(int worker_i,
+                           G1RemSet* g1rs,
+                           DirtyCardQueue* into_cset_dcq) {
+  if (!default_use_cache()) {
+    assert(_hot_cache == NULL, "Logic");
+    return;
+  }
+
+  assert(_hot_cache != NULL, "Logic");
+  assert(!use_cache(), "cache should be disabled");
+  int start_idx;
+
+  while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once
+    int end_idx = start_idx + _hot_cache_par_chunk_size;
+
+    if (start_idx ==
+        Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) {
+      // The current worker has successfully claimed the chunk [start_idx..end_idx)
+      end_idx = MIN2(end_idx, _n_hot);
+      for (int i = start_idx; i < end_idx; i++) {
+        jbyte* card_ptr = _hot_cache[i];
+        if (card_ptr != NULL) {
+          if (g1rs->refine_card(card_ptr, worker_i, true)) {
+            // The part of the heap spanned by the card contains references
+            // that point into the current collection set.
+            // We need to record the card pointer in the DirtyCardQueueSet
+            // that we use for such cards.
+            //
+            // The only time we care about recording cards that contain
+            // references that point into the collection set is during
+            // RSet updating while within an evacuation pause.
+            // In this case worker_i should be the id of a GC worker thread
+            assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
+            assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads),
+                   err_msg("incorrect worker id: "INT32_FORMAT, worker_i));
+
+            into_cset_dcq->enqueue(card_ptr);
+          }
+        }
+      }
+    }
+  }
+  // The existing entries in the hot card cache, which were just refined
+  // above, are discarded prior to re-enabling the cache near the end of the GC.
+}
+
+void G1HotCardCache::resize_card_counts(size_t heap_capacity) {
+  _card_counts.resize(heap_capacity);
+}
+
+void G1HotCardCache::reset_card_counts(HeapRegion* hr) {
+  _card_counts.clear_region(hr);
+}
+
+void G1HotCardCache::reset_card_counts() {
+  _card_counts.clear_all();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.hpp	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1HOTCARDCACHE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1HOTCARDCACHE_HPP
+
+#include "gc_implementation/g1/g1_globals.hpp"
+#include "gc_implementation/g1/g1CardCounts.hpp"
+#include "memory/allocation.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class DirtyCardQueue;
+class G1CollectedHeap;
+class G1RemSet;
+class HeapRegion;
+
+// An evicting cache of cards that have been logged by the G1 post
+// write barrier. Placing a card in the cache delays the refinement
+// of the card until the card is evicted, or the cache is drained
+// during the next evacuation pause.
+//
+// The first thing the G1 post write barrier does is to check whether
+// the card containing the updated pointer is already dirty and, if
+// so, skips the remaining code in the barrier.
+//
+// Delaying the refinement of a card will make the card fail the
+// first is_dirty check in the write barrier, skipping the remainder
+// of the write barrier.
+//
+// This can significantly reduce the overhead of the write barrier
+// code, increasing throughput.
+
+class G1HotCardCache: public CHeapObj<mtGC> {
+  G1CollectedHeap*   _g1h;
+
+  // The card cache table
+  jbyte**      _hot_cache;
+
+  int          _hot_cache_size;
+  int          _n_hot;
+  int          _hot_cache_idx;
+
+  int          _hot_cache_par_chunk_size;
+  volatile int _hot_cache_par_claimed_idx;
+
+  bool         _use_cache;
+
+  G1CardCounts _card_counts;
+
+  bool default_use_cache() const {
+    return (G1ConcRSLogCacheSize > 0);
+  }
+
+ public:
+  G1HotCardCache(G1CollectedHeap* g1h);
+  ~G1HotCardCache();
+
+  void initialize();
+
+  bool use_cache() { return _use_cache; }
+
+  void set_use_cache(bool b) {
+    _use_cache = (b ? default_use_cache() : false);
+  }
+
+  // Returns the card to be refined or NULL.
+  //
+  // Increments the count for given the card. if the card is not 'hot',
+  // it is returned for immediate refining. Otherwise the card is
+  // added to the hot card cache.
+  // If there is enough room in the hot card cache for the card we're
+  // adding, NULL is returned and no further action in needed.
+  // If we evict a card from the cache to make room for the new card,
+  // the evicted card is then returned for refinement.
+  jbyte* insert(jbyte* card_ptr);
+
+  // Refine the cards that have delayed as a result of
+  // being in the cache.
+  void drain(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq);
+
+  // Set up for parallel processing of the cards in the hot cache
+  void reset_hot_cache_claimed_index() {
+    _hot_cache_par_claimed_idx = 0;
+  }
+
+  // Resets the hot card cache and discards the entries.
+  void reset_hot_cache() {
+    assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
+    assert(Thread::current()->is_VM_thread(), "Current thread should be the VMthread");
+    _hot_cache_idx = 0; _n_hot = 0;
+  }
+
+  bool hot_cache_is_empty() { return _n_hot == 0; }
+
+  // Resizes the card counts table to match the given capacity
+  void resize_card_counts(size_t heap_capacity);
+
+  // Zeros the values in the card counts table for entire committed heap
+  void reset_card_counts();
+
+  // Zeros the values in the card counts table for the given region
+  void reset_card_counts(HeapRegion* hr);
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1HOTCARDCACHE_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp	Thu May 16 11:47:51 2013 +0100
@@ -144,33 +144,28 @@
                                     &GenMarkSweep::follow_stack_closure,
                                     NULL);
 
-  // Follow system dictionary roots and unload classes
+
+  // This is the point where the entire marking should have completed.
+  assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed");
+
+  // Unload classes and purge the SystemDictionary.
   bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
-  assert(GenMarkSweep::_marking_stack.is_empty(),
-         "stack should be empty by now");
 
-  // Follow code cache roots (has to be done after system dictionary,
-  // assumes all live klasses are marked)
+  // Unload nmethods.
   CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class);
-  GenMarkSweep::follow_stack();
 
-  // Update subklass/sibling/implementor links of live klasses
+  // Prune dead klasses from subklass/sibling/implementor lists.
   Klass::clean_weak_klass_links(&GenMarkSweep::is_alive);
-  assert(GenMarkSweep::_marking_stack.is_empty(),
-         "stack should be empty by now");
 
-  // Visit interned string tables and delete unmarked oops
+  // Delete entries for dead interned strings.
   StringTable::unlink(&GenMarkSweep::is_alive);
+
   // Clean up unreferenced symbols in symbol table.
   SymbolTable::unlink();
 
-  assert(GenMarkSweep::_marking_stack.is_empty(),
-         "stack should be empty by now");
-
   if (VerifyDuringGC) {
     HandleMark hm;  // handle scope
     COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact);
-    gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying ");
     Universe::heap()->prepare_for_verify();
     // Note: we can verify only the heap here. When an object is
     // marked, the previous value of the mark word (including
@@ -182,11 +177,13 @@
     // fail. At the end of the GC, the orginal mark word values
     // (including hash values) are restored to the appropriate
     // objects.
-    Universe::heap()->verify(/* silent      */ false,
-                             /* option      */ VerifyOption_G1UseMarkWord);
-
-    G1CollectedHeap* g1h = G1CollectedHeap::heap();
-    gclog_or_tty->print_cr("]");
+    if (!VerifySilently) {
+      gclog_or_tty->print(" VerifyDuringGC:(full)[Verifying ");
+    }
+    Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord);
+    if (!VerifySilently) {
+      gclog_or_tty->print_cr("]");
+    }
   }
 }
 
@@ -308,17 +305,16 @@
   sh->process_strong_roots(true,  // activate StrongRootsScope
                            false, // not scavenging.
                            SharedHeap::SO_AllClasses,
-                           &GenMarkSweep::adjust_root_pointer_closure,
+                           &GenMarkSweep::adjust_pointer_closure,
                            NULL,  // do not touch code cache here
                            &GenMarkSweep::adjust_klass_closure);
 
   assert(GenMarkSweep::ref_processor() == g1h->ref_processor_stw(), "Sanity");
-  g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure);
+  g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_pointer_closure);
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
-  g1h->g1_process_weak_roots(&GenMarkSweep::adjust_root_pointer_closure,
-                             &GenMarkSweep::adjust_pointer_closure);
+  g1h->g1_process_weak_roots(&GenMarkSweep::adjust_pointer_closure);
 
   GenMarkSweep::adjust_marks();
 
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
+#include "gc_implementation/g1/g1HotCardCache.hpp"
 #include "gc_implementation/g1/g1GCPhaseTimes.hpp"
 #include "gc_implementation/g1/g1OopClosures.inline.hpp"
 #include "gc_implementation/g1/g1RemSet.inline.hpp"
@@ -169,14 +170,13 @@
     //   _try_claimed || r->claim_iter()
     // is true: either we're supposed to work on claimed-but-not-complete
     // regions, or we successfully claimed the region.
-    HeapRegionRemSetIterator* iter = _g1h->rem_set_iterator(_worker_i);
-    hrrs->init_iterator(iter);
+    HeapRegionRemSetIterator iter(hrrs);
     size_t card_index;
 
     // We claim cards in block so as to recude the contention. The block size is determined by
     // the G1RSetScanBlockSize parameter.
     size_t jump_to_card = hrrs->iter_claimed_next(_block_size);
-    for (size_t current_card = 0; iter->has_next(card_index); current_card++) {
+    for (size_t current_card = 0; iter.has_next(card_index); current_card++) {
       if (current_card >= jump_to_card + _block_size) {
         jump_to_card = hrrs->iter_claimed_next(_block_size);
       }
@@ -248,7 +248,7 @@
     assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
     assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker");
 
-    if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) {
+    if (_g1rs->refine_card(card_ptr, worker_i, true)) {
       // 'card_ptr' contains references that point into the collection
       // set. We need to record the card in the DCQS
       // (G1CollectedHeap::into_cset_dirty_card_queue_set())
@@ -289,9 +289,6 @@
 #if CARD_REPEAT_HISTO
   ct_freq_update_histo_and_reset();
 #endif
-  if (worker_i == 0) {
-    _cg1r->clear_and_record_card_counts();
-  }
 
   // We cache the value of 'oc' closure into the appropriate slot in the
   // _cset_rs_update_cl for this worker
@@ -397,7 +394,7 @@
     //   RSet updating,
     // * the post-write barrier shouldn't be logging updates to young
     //   regions (but there is a situation where this can happen - see
-    //   the comment in G1RemSet::concurrentRefineOneCard below -
+    //   the comment in G1RemSet::refine_card() below -
     //   that should not be applicable here), and
     // * during actual RSet updating, the filtering of cards in young
     //   regions in HeapRegion::oops_on_card_seq_iterate_careful is
@@ -503,8 +500,6 @@
                                        claim_val);
 }
 
-
-
 G1TriggerClosure::G1TriggerClosure() :
   _triggered(false) { }
 
@@ -525,13 +520,91 @@
   _record_refs_into_cset(record_refs_into_cset),
   _push_ref_cl(push_ref_cl), _worker_i(worker_i) { }
 
-bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
-                                                   bool check_for_refs_into_cset) {
+// Returns true if the given card contains references that point
+// into the collection set, if we're checking for such references;
+// false otherwise.
+
+bool G1RemSet::refine_card(jbyte* card_ptr, int worker_i,
+                           bool check_for_refs_into_cset) {
+
+  // If the card is no longer dirty, nothing to do.
+  if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
+    // No need to return that this card contains refs that point
+    // into the collection set.
+    return false;
+  }
+
   // Construct the region representing the card.
   HeapWord* start = _ct_bs->addr_for(card_ptr);
   // And find the region containing it.
   HeapRegion* r = _g1->heap_region_containing(start);
-  assert(r != NULL, "unexpected null");
+  if (r == NULL) {
+    // Again no need to return that this card contains refs that
+    // point into the collection set.
+    return false;  // Not in the G1 heap (might be in perm, for example.)
+  }
+
+  // Why do we have to check here whether a card is on a young region,
+  // given that we dirty young regions and, as a result, the
+  // post-barrier is supposed to filter them out and never to enqueue
+  // them? When we allocate a new region as the "allocation region" we
+  // actually dirty its cards after we release the lock, since card
+  // dirtying while holding the lock was a performance bottleneck. So,
+  // as a result, it is possible for other threads to actually
+  // allocate objects in the region (after the acquire the lock)
+  // before all the cards on the region are dirtied. This is unlikely,
+  // and it doesn't happen often, but it can happen. So, the extra
+  // check below filters out those cards.
+  if (r->is_young()) {
+    return false;
+  }
+
+  // While we are processing RSet buffers during the collection, we
+  // actually don't want to scan any cards on the collection set,
+  // since we don't want to update remebered sets with entries that
+  // point into the collection set, given that live objects from the
+  // collection set are about to move and such entries will be stale
+  // very soon. This change also deals with a reliability issue which
+  // involves scanning a card in the collection set and coming across
+  // an array that was being chunked and looking malformed. Note,
+  // however, that if evacuation fails, we have to scan any objects
+  // that were not moved and create any missing entries.
+  if (r->in_collection_set()) {
+    return false;
+  }
+
+  // The result from the hot card cache insert call is either:
+  //   * pointer to the current card
+  //     (implying that the current card is not 'hot'),
+  //   * null
+  //     (meaning we had inserted the card ptr into the "hot" card cache,
+  //     which had some headroom),
+  //   * a pointer to a "hot" card that was evicted from the "hot" cache.
+  //
+
+  G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
+  if (hot_card_cache->use_cache()) {
+    assert(!check_for_refs_into_cset, "sanity");
+    assert(!SafepointSynchronize::is_at_safepoint(), "sanity");
+
+    card_ptr = hot_card_cache->insert(card_ptr);
+    if (card_ptr == NULL) {
+      // There was no eviction. Nothing to do.
+      return false;
+    }
+
+    start = _ct_bs->addr_for(card_ptr);
+    r = _g1->heap_region_containing(start);
+    if (r == NULL) {
+      // Not in the G1 heap
+      return false;
+    }
+
+    // Checking whether the region we got back from the cache
+    // is young here is inappropriate. The region could have been
+    // freed, reallocated and tagged as young while in the cache.
+    // Hence we could see its young type change at any time.
+  }
 
   // Don't use addr_for(card_ptr + 1) which can ask for
   // a card beyond the heap.  This is not safe without a perm
@@ -611,140 +684,17 @@
     _conc_refine_cards++;
   }
 
-  return trigger_cl.triggered();
-}
-
-bool G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
-                                              bool check_for_refs_into_cset) {
-  // If the card is no longer dirty, nothing to do.
-  if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
-    // No need to return that this card contains refs that point
-    // into the collection set.
-    return false;
-  }
-
-  // Construct the region representing the card.
-  HeapWord* start = _ct_bs->addr_for(card_ptr);
-  // And find the region containing it.
-  HeapRegion* r = _g1->heap_region_containing(start);
-  if (r == NULL) {
-    // Again no need to return that this card contains refs that
-    // point into the collection set.
-    return false;  // Not in the G1 heap (might be in perm, for example.)
-  }
-  // Why do we have to check here whether a card is on a young region,
-  // given that we dirty young regions and, as a result, the
-  // post-barrier is supposed to filter them out and never to enqueue
-  // them? When we allocate a new region as the "allocation region" we
-  // actually dirty its cards after we release the lock, since card
-  // dirtying while holding the lock was a performance bottleneck. So,
-  // as a result, it is possible for other threads to actually
-  // allocate objects in the region (after the acquire the lock)
-  // before all the cards on the region are dirtied. This is unlikely,
-  // and it doesn't happen often, but it can happen. So, the extra
-  // check below filters out those cards.
-  if (r->is_young()) {
-    return false;
-  }
-  // While we are processing RSet buffers during the collection, we
-  // actually don't want to scan any cards on the collection set,
-  // since we don't want to update remebered sets with entries that
-  // point into the collection set, given that live objects from the
-  // collection set are about to move and such entries will be stale
-  // very soon. This change also deals with a reliability issue which
-  // involves scanning a card in the collection set and coming across
-  // an array that was being chunked and looking malformed. Note,
-  // however, that if evacuation fails, we have to scan any objects
-  // that were not moved and create any missing entries.
-  if (r->in_collection_set()) {
-    return false;
-  }
+  // This gets set to true if the card being refined has
+  // references that point into the collection set.
+  bool has_refs_into_cset = trigger_cl.triggered();
 
-  // Should we defer processing the card?
-  //
-  // Previously the result from the insert_cache call would be
-  // either card_ptr (implying that card_ptr was currently "cold"),
-  // null (meaning we had inserted the card ptr into the "hot"
-  // cache, which had some headroom), or a "hot" card ptr
-  // extracted from the "hot" cache.
-  //
-  // Now that the _card_counts cache in the ConcurrentG1Refine
-  // instance is an evicting hash table, the result we get back
-  // could be from evicting the card ptr in an already occupied
-  // bucket (in which case we have replaced the card ptr in the
-  // bucket with card_ptr and "defer" is set to false). To avoid
-  // having a data structure (updates to which would need a lock)
-  // to hold these unprocessed dirty cards, we need to immediately
-  // process card_ptr. The actions needed to be taken on return
-  // from cache_insert are summarized in the following table:
-  //
-  // res      defer   action
-  // --------------------------------------------------------------
-  // null     false   card evicted from _card_counts & replaced with
-  //                  card_ptr; evicted ptr added to hot cache.
-  //                  No need to process res; immediately process card_ptr
-  //
-  // null     true    card not evicted from _card_counts; card_ptr added
-  //                  to hot cache.
-  //                  Nothing to do.
-  //
-  // non-null false   card evicted from _card_counts & replaced with
-  //                  card_ptr; evicted ptr is currently "cold" or
-  //                  caused an eviction from the hot cache.
-  //                  Immediately process res; process card_ptr.
-  //
-  // non-null true    card not evicted from _card_counts; card_ptr is
-  //                  currently cold, or caused an eviction from hot
-  //                  cache.
-  //                  Immediately process res; no need to process card_ptr.
-
-
-  jbyte* res = card_ptr;
-  bool defer = false;
+  // We should only be detecting that the card contains references
+  // that point into the collection set if the current thread is
+  // a GC worker thread.
+  assert(!has_refs_into_cset || SafepointSynchronize::is_at_safepoint(),
+           "invalid result at non safepoint");
 
-  // This gets set to true if the card being refined has references
-  // that point into the collection set.
-  bool oops_into_cset = false;
-
-  if (_cg1r->use_cache()) {
-    jbyte* res = _cg1r->cache_insert(card_ptr, &defer);
-    if (res != NULL && (res != card_ptr || defer)) {
-      start = _ct_bs->addr_for(res);
-      r = _g1->heap_region_containing(start);
-      if (r != NULL) {
-        // Checking whether the region we got back from the cache
-        // is young here is inappropriate. The region could have been
-        // freed, reallocated and tagged as young while in the cache.
-        // Hence we could see its young type change at any time.
-        //
-        // Process card pointer we get back from the hot card cache. This
-        // will check whether the region containing the card is young
-        // _after_ checking that the region has been allocated from.
-        oops_into_cset = concurrentRefineOneCard_impl(res, worker_i,
-                                                      false /* check_for_refs_into_cset */);
-        // The above call to concurrentRefineOneCard_impl is only
-        // performed if the hot card cache is enabled. This cache is
-        // disabled during an evacuation pause - which is the only
-        // time when we need know if the card contains references
-        // that point into the collection set. Also when the hot card
-        // cache is enabled, this code is executed by the concurrent
-        // refine threads - rather than the GC worker threads - and
-        // concurrentRefineOneCard_impl will return false.
-        assert(!oops_into_cset, "should not see true here");
-      }
-    }
-  }
-
-  if (!defer) {
-    oops_into_cset =
-      concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset);
-    // We should only be detecting that the card contains references
-    // that point into the collection set if the current thread is
-    // a GC worker thread.
-    assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(),
-           "invalid result at non safepoint");
-  }
-  return oops_into_cset;
+  return has_refs_into_cset;
 }
 
 class HRRSStatsIter: public HeapRegionClosure {
@@ -847,13 +797,16 @@
       DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
       dcqs.concatenate_logs();
     }
-    bool cg1r_use_cache = _cg1r->use_cache();
-    _cg1r->set_use_cache(false);
+
+    G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
+    bool use_hot_card_cache = hot_card_cache->use_cache();
+    hot_card_cache->set_use_cache(false);
+
     DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set());
     updateRS(&into_cset_dcq, 0);
     _g1->into_cset_dirty_card_queue_set().clear();
-    _cg1r->set_use_cache(cg1r_use_cache);
 
+    hot_card_cache->set_use_cache(use_hot_card_cache);
     assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
   }
 }
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,27 +53,19 @@
     NumSeqTasks          = 1
   };
 
-  CardTableModRefBS*             _ct_bs;
-  SubTasksDone*                  _seq_task;
-  G1CollectorPolicy* _g1p;
+  CardTableModRefBS*     _ct_bs;
+  SubTasksDone*          _seq_task;
+  G1CollectorPolicy*     _g1p;
 
-  ConcurrentG1Refine* _cg1r;
+  ConcurrentG1Refine*    _cg1r;
 
-  size_t*             _cards_scanned;
-  size_t              _total_cards_scanned;
+  size_t*                _cards_scanned;
+  size_t                 _total_cards_scanned;
 
   // Used for caching the closure that is responsible for scanning
   // references into the collection set.
   OopsInHeapRegionClosure** _cset_rs_update_cl;
 
-  // The routine that performs the actual work of refining a dirty
-  // card.
-  // If check_for_refs_into_refs is true then a true result is returned
-  // if the card contains oops that have references into the current
-  // collection set.
-  bool concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
-                                    bool check_for_refs_into_cset);
-
 public:
   // This is called to reset dual hash tables after the gc pause
   // is finished and the initial hash table is no longer being
@@ -90,8 +82,7 @@
   // function can be helpful in partitioning the work to be done. It
   // should be the same as the "i" passed to the calling thread's
   // work(i) function. In the sequential case this param will be ingored.
-  void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
-                                   int worker_i);
+  void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, int worker_i);
 
   // Prepare for and cleanup after an oops_into_collection_set_do
   // call.  Must call each of these once before and after (in sequential
@@ -124,14 +115,13 @@
   void scrub_par(BitMap* region_bm, BitMap* card_bm,
                  uint worker_num, int claim_val);
 
-  // Refine the card corresponding to "card_ptr".  If "sts" is non-NULL,
-  // join and leave around parts that must be atomic wrt GC.  (NULL means
-  // being done at a safepoint.)
+  // Refine the card corresponding to "card_ptr".
   // If check_for_refs_into_cset is true, a true result is returned
   // if the given card contains oops that have references into the
   // current collection set.
-  virtual bool concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
-                                       bool check_for_refs_into_cset);
+  virtual bool refine_card(jbyte* card_ptr,
+                           int worker_i,
+                           bool check_for_refs_into_cset);
 
   // Print any relevant summary info.
   virtual void print_summary_info();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp	Thu May 16 11:47:51 2013 +0100
@@ -163,16 +163,12 @@
           "Select green, yellow and red zones adaptively to meet the "      \
           "the pause requirements.")                                        \
                                                                             \
-  develop(intx, G1ConcRSLogCacheSize, 10,                                   \
+  product(uintx, G1ConcRSLogCacheSize, 10,                                  \
           "Log base 2 of the length of conc RS hot-card cache.")            \
                                                                             \
-  develop(intx, G1ConcRSHotCardLimit, 4,                                    \
+  product(uintx, G1ConcRSHotCardLimit, 4,                                   \
           "The threshold that defines (>=) a hot card.")                    \
                                                                             \
-  develop(intx, G1MaxHotCardCountSizePercent, 25,                           \
-          "The maximum size of the hot card count cache as a "              \
-          "percentage of the number of cards for the maximum heap.")        \
-                                                                            \
   develop(bool, G1PrintOopAppls, false,                                     \
           "When true, print applications of closures to external locs.")    \
                                                                             \
@@ -247,10 +243,6 @@
           "If non-0 is the number of parallel rem set update threads, "     \
           "otherwise the value is determined ergonomically.")               \
                                                                             \
-  develop(intx, G1CardCountCacheExpandThreshold, 16,                        \
-          "Expand the card count cache if the number of collisions for "    \
-          "a particular entry exceeds this value.")                         \
-                                                                            \
   develop(bool, G1VerifyCTCleanup, false,                                   \
           "Verify card table cleanup.")                                     \
                                                                             \
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Thu May 16 11:47:51 2013 +0100
@@ -285,7 +285,7 @@
   _fine_grain_regions = new PerRegionTablePtr[_max_fine_entries];
 
   if (_fine_grain_regions == NULL) {
-    vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
+    vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries, OOM_MALLOC_ERROR,
                           "Failed to allocate _fine_grain_entries.");
   }
 
@@ -877,14 +877,9 @@
   return _iter_state == Complete;
 }
 
-void HeapRegionRemSet::init_iterator(HeapRegionRemSetIterator* iter) const {
-  iter->initialize(this);
-}
-
 #ifndef PRODUCT
 void HeapRegionRemSet::print() const {
-  HeapRegionRemSetIterator iter;
-  init_iterator(&iter);
+  HeapRegionRemSetIterator iter(this);
   size_t card_index;
   while (iter.has_next(card_index)) {
     HeapWord* card_start =
@@ -928,35 +923,23 @@
 
 //-------------------- Iteration --------------------
 
-HeapRegionRemSetIterator::
-HeapRegionRemSetIterator() :
-  _hrrs(NULL),
+HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) :
+  _hrrs(hrrs),
   _g1h(G1CollectedHeap::heap()),
-  _bosa(NULL),
-  _sparse_iter() { }
-
-void HeapRegionRemSetIterator::initialize(const HeapRegionRemSet* hrrs) {
-  _hrrs = hrrs;
-  _coarse_map = &_hrrs->_other_regions._coarse_map;
-  _fine_grain_regions = _hrrs->_other_regions._fine_grain_regions;
-  _bosa = _hrrs->bosa();
-
-  _is = Sparse;
+  _coarse_map(&hrrs->_other_regions._coarse_map),
+  _fine_grain_regions(hrrs->_other_regions._fine_grain_regions),
+  _bosa(hrrs->bosa()),
+  _is(Sparse),
   // Set these values so that we increment to the first region.
-  _coarse_cur_region_index = -1;
-  _coarse_cur_region_cur_card = (HeapRegion::CardsPerRegion-1);
-
-  _cur_region_cur_card = 0;
-
-  _fine_array_index = -1;
-  _fine_cur_prt = NULL;
-
-  _n_yielded_coarse = 0;
-  _n_yielded_fine = 0;
-  _n_yielded_sparse = 0;
-
-  _sparse_iter.init(&hrrs->_other_regions._sparse_table);
-}
+  _coarse_cur_region_index(-1),
+  _coarse_cur_region_cur_card(HeapRegion::CardsPerRegion-1),
+  _cur_region_cur_card(0),
+  _fine_array_index(-1),
+  _fine_cur_prt(NULL),
+  _n_yielded_coarse(0),
+  _n_yielded_fine(0),
+  _n_yielded_sparse(0),
+  _sparse_iter(&hrrs->_other_regions._sparse_table) {}
 
 bool HeapRegionRemSetIterator::coarse_has_next(size_t& card_index) {
   if (_hrrs->_other_regions._n_coarse_entries == 0) return false;
@@ -1209,8 +1192,7 @@
   hrrs->add_reference((OopOrNarrowOopStar)hr5->bottom());
 
   // Now, does iteration yield these three?
-  HeapRegionRemSetIterator iter;
-  hrrs->init_iterator(&iter);
+  HeapRegionRemSetIterator iter(hrrs);
   size_t sum = 0;
   size_t card_index;
   while (iter.has_next(card_index)) {
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Thu May 16 11:47:51 2013 +0100
@@ -281,9 +281,6 @@
     return (_iter_state == Unclaimed) && (_iter_claimed == 0);
   }
 
-  // Initialize the given iterator to iterate over this rem set.
-  void init_iterator(HeapRegionRemSetIterator* iter) const;
-
   // The actual # of bytes this hr_remset takes up.
   size_t mem_size() {
     return _other_regions.mem_size()
@@ -345,9 +342,9 @@
 #endif
 };
 
-class HeapRegionRemSetIterator : public CHeapObj<mtGC> {
+class HeapRegionRemSetIterator : public StackObj {
 
-  // The region over which we're iterating.
+  // The region RSet over which we're iterating.
   const HeapRegionRemSet* _hrrs;
 
   // Local caching of HRRS fields.
@@ -362,8 +359,10 @@
   size_t _n_yielded_coarse;
   size_t _n_yielded_sparse;
 
-  // If true we're iterating over the coarse table; if false the fine
-  // table.
+  // Indicates what granularity of table that we're currently iterating over.
+  // We start iterating over the sparse table, progress to the fine grain
+  // table, and then finish with the coarse table.
+  // See HeapRegionRemSetIterator::has_next().
   enum IterState {
     Sparse,
     Fine,
@@ -403,9 +402,7 @@
 public:
   // We require an iterator to be initialized before use, so the
   // constructor does little.
-  HeapRegionRemSetIterator();
-
-  void initialize(const HeapRegionRemSet* hrrs);
+  HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs);
 
   // If there remains one or more cards to be yielded, returns true and
   // sets "card_index" to one of those cards (which is then considered
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp	Thu May 16 11:47:51 2013 +0100
@@ -124,11 +124,11 @@
       }
       assert(_regions[index] == NULL, "invariant");
       _regions[index] = new_hr;
-      increment_length(&_allocated_length);
+      increment_allocated_length();
     }
     // Have to increment the length first, otherwise we will get an
     // assert failure at(index) below.
-    increment_length(&_length);
+    increment_length();
     HeapRegion* hr = at(index);
     list->add_as_tail(hr);
 
@@ -201,45 +201,29 @@
   }
 }
 
-MemRegion HeapRegionSeq::shrink_by(size_t shrink_bytes,
-                                   uint* num_regions_deleted) {
+uint HeapRegionSeq::shrink_by(uint num_regions_to_remove) {
   // Reset this in case it's currently pointing into the regions that
   // we just removed.
   _next_search_index = 0;
 
-  assert(shrink_bytes % os::vm_page_size() == 0, "unaligned");
-  assert(shrink_bytes % HeapRegion::GrainBytes == 0, "unaligned");
   assert(length() > 0, "the region sequence should not be empty");
   assert(length() <= _allocated_length, "invariant");
   assert(_allocated_length > 0, "we should have at least one region committed");
+  assert(num_regions_to_remove < length(), "We should never remove all regions");
 
-  // around the loop, i will be the next region to be removed
-  uint i = length() - 1;
-  assert(i > 0, "we should never remove all regions");
-  // [last_start, end) is the MemRegion that covers the regions we will remove.
-  HeapWord* end = at(i)->end();
-  HeapWord* last_start = end;
-  *num_regions_deleted = 0;
-  while (shrink_bytes > 0) {
-    HeapRegion* cur = at(i);
-    // We should leave the humongous regions where they are.
-    if (cur->isHumongous()) break;
-    // We should stop shrinking if we come across a non-empty region.
-    if (!cur->is_empty()) break;
+  uint i = 0;
+  for (; i < num_regions_to_remove; i++) {
+    HeapRegion* cur = at(length() - 1);
 
-    i -= 1;
-    *num_regions_deleted += 1;
-    shrink_bytes -= cur->capacity();
-    last_start = cur->bottom();
-    decrement_length(&_length);
-    // We will reclaim the HeapRegion. _allocated_length should be
-    // covering this index. So, even though we removed the region from
-    // the active set by decreasing _length, we still have it
-    // available in the future if we need to re-use it.
-    assert(i > 0, "we should never remove all regions");
-    assert(length() > 0, "we should never remove all regions");
+    if (!cur->is_empty()) {
+      // We have to give up if the region can not be moved
+      break;
   }
-  return MemRegion(last_start, end);
+    assert(!cur->isHumongous(), "Humongous regions should not be empty");
+
+    decrement_length();
+  }
+  return i;
 }
 
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.hpp	Thu May 16 11:47:51 2013 +0100
@@ -92,14 +92,19 @@
   // address is valid.
   inline uintx addr_to_index_biased(HeapWord* addr) const;
 
-  void increment_length(uint* length) {
-    assert(*length < _max_length, "pre-condition");
-    *length += 1;
+  void increment_allocated_length() {
+    assert(_allocated_length < _max_length, "pre-condition");
+    _allocated_length++;
   }
 
-  void decrement_length(uint* length) {
-    assert(*length > 0, "pre-condition");
-    *length -= 1;
+  void increment_length() {
+    assert(_length < _max_length, "pre-condition");
+    _length++;
+  }
+
+  void decrement_length() {
+    assert(_length > 0, "pre-condition");
+    _length--;
   }
 
  public:
@@ -153,11 +158,9 @@
   void iterate_from(HeapRegion* hr, HeapRegionClosure* blk) const;
 
   // Tag as uncommitted as many regions that are completely free as
-  // possible, up to shrink_bytes, from the suffix of the committed
-  // sequence. Return a MemRegion that corresponds to the address
-  // range of the uncommitted regions. Assume shrink_bytes is page and
-  // heap region aligned.
-  MemRegion shrink_by(size_t shrink_bytes, uint* num_regions_deleted);
+  // possible, up to num_regions_to_remove, from the suffix of the committed
+  // sequence. Return the actual number of removed regions.
+  uint shrink_by(uint num_regions_to_remove);
 
   // Do some sanity checking.
   void verify_optional() PRODUCT_RETURN;
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.cpp	Thu May 16 11:47:51 2013 +0100
@@ -35,10 +35,6 @@
 
 #define UNROLL_CARD_LOOPS  1
 
-void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) {
-    sprt_iter->init(this);
-}
-
 void SparsePRTEntry::init(RegionIdx_t region_ind) {
   _region_ind = region_ind;
   _next_index = NullEntry;
--- a/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/g1/sparsePRT.hpp	Thu May 16 11:47:51 2013 +0100
@@ -192,18 +192,11 @@
   size_t compute_card_ind(CardIdx_t ci);
 
 public:
-  RSHashTableIter() :
-    _tbl_ind(RSHashTable::NullEntry),
+  RSHashTableIter(RSHashTable* rsht) :
+    _tbl_ind(RSHashTable::NullEntry), // So that first increment gets to 0.
     _bl_ind(RSHashTable::NullEntry),
     _card_ind((SparsePRTEntry::cards_num() - 1)),
-    _rsht(NULL) {}
-
-  void init(RSHashTable* rsht) {
-    _rsht = rsht;
-    _tbl_ind = -1; // So that first increment gets to 0.
-    _bl_ind = RSHashTable::NullEntry;
-    _card_ind = (SparsePRTEntry::cards_num() - 1);
-  }
+    _rsht(rsht) {}
 
   bool has_next(size_t& card_index);
 };
@@ -284,8 +277,6 @@
   static void cleanup_all();
   RSHashTable* cur() const { return _cur; }
 
-  void init_iterator(SparsePRTIter* sprt_iter);
-
   static void add_to_expanded_list(SparsePRT* sprt);
   static SparsePRT* get_from_expanded_list();
 
@@ -321,9 +312,9 @@
 
 class SparsePRTIter: public RSHashTableIter {
 public:
-  void init(const SparsePRT* sprt) {
-    RSHashTableIter::init(sprt->cur());
-  }
+  SparsePRTIter(const SparsePRT* sprt) :
+    RSHashTableIter(sprt->cur()) {}
+
   bool has_next(size_t& card_index) {
     return RSHashTableIter::has_next(card_index);
   }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/cardTableExtension.cpp	Thu May 16 11:47:51 2013 +0100
@@ -567,7 +567,7 @@
         MemRegion(new_start_aligned, new_end_for_commit);
       if (!os::commit_memory((char*)new_committed.start(),
                              new_committed.byte_size())) {
-        vm_exit_out_of_memory(new_committed.byte_size(),
+        vm_exit_out_of_memory(new_committed.byte_size(), OOM_MMAP_ERROR,
                               "card table expansion");
       }
     }
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp	Thu May 16 11:47:51 2013 +0100
@@ -43,7 +43,7 @@
   _time_stamp_index(0)
 {
   if (!os::create_thread(this, os::pgc_thread))
-    vm_exit_out_of_memory(0, "Cannot create GC thread. Out of system resources.");
+    vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GC thread. Out of system resources.");
 
   if (PrintGCTaskTimeStamps) {
     _time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/objectStartArray.cpp	Thu May 16 11:47:51 2013 +0100
@@ -99,7 +99,7 @@
     // Expand
     size_t expand_by = requested_blocks_size_in_bytes - current_blocks_size_in_bytes;
     if (!_virtual_space.expand_by(expand_by)) {
-      vm_exit_out_of_memory(expand_by, "object start array expansion");
+      vm_exit_out_of_memory(expand_by, OOM_MMAP_ERROR, "object start array expansion");
     }
     // Clear *only* the newly allocated region
     memset(_blocks_region.end(), clean_block, expand_by);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp	Thu May 16 11:47:51 2013 +0100
@@ -138,8 +138,7 @@
 
   if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyBeforeGC:");
-    Universe::verify();
+    Universe::verify(" VerifyBeforeGC:");
   }
 
   // Verify object start arrays
@@ -177,7 +176,7 @@
     size_t prev_used = heap->used();
 
     // Capture metadata size before collection for sizing.
-    size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+    size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
 
     // For PrintGCDetails
     size_t old_gen_prev_used = old_gen->used_in_bytes();
@@ -238,6 +237,7 @@
 
     // Delete metaspaces for unloaded class loaders and clean up loader_data graph
     ClassLoaderDataGraph::purge();
+    MetaspaceAux::verify_metrics();
 
     BiasedLocking::restore_marks();
     Threads::gc_epilogue();
@@ -340,8 +340,7 @@
 
   if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyAfterGC:");
-    Universe::verify();
+    Universe::verify(" VerifyAfterGC:");
   }
 
   // Re-verify object start arrays
@@ -518,23 +517,23 @@
       is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL);
   }
 
-  // Follow system dictionary roots and unload classes
+  // This is the point where the entire marking should have completed.
+  assert(_marking_stack.is_empty(), "Marking should have completed");
+
+  // Unload classes and purge the SystemDictionary.
   bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
 
-  // Follow code cache roots
+  // Unload nmethods.
   CodeCache::do_unloading(is_alive_closure(), purged_class);
-  follow_stack(); // Flush marking stack
 
-  // Update subklass/sibling/implementor links of live klasses
-  Klass::clean_weak_klass_links(&is_alive);
-  assert(_marking_stack.is_empty(), "just drained");
+  // Prune dead klasses from subklass/sibling/implementor lists.
+  Klass::clean_weak_klass_links(is_alive_closure());
 
-  // Visit interned string tables and delete unmarked oops
+  // Delete entries for dead interned strings.
   StringTable::unlink(is_alive_closure());
+
   // Clean up unreferenced symbols in symbol table.
   SymbolTable::unlink();
-
-  assert(_marking_stack.is_empty(), "stack should be empty by now");
 }
 
 
@@ -583,28 +582,27 @@
   ClassLoaderDataGraph::clear_claimed_marks();
 
   // General strong roots.
-  Universe::oops_do(adjust_root_pointer_closure());
-  JNIHandles::oops_do(adjust_root_pointer_closure());   // Global (strong) JNI handles
-  CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
-  Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
-  ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
-  FlatProfiler::oops_do(adjust_root_pointer_closure());
-  Management::oops_do(adjust_root_pointer_closure());
-  JvmtiExport::oops_do(adjust_root_pointer_closure());
+  Universe::oops_do(adjust_pointer_closure());
+  JNIHandles::oops_do(adjust_pointer_closure());   // Global (strong) JNI handles
+  CLDToOopClosure adjust_from_cld(adjust_pointer_closure());
+  Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL);
+  ObjectSynchronizer::oops_do(adjust_pointer_closure());
+  FlatProfiler::oops_do(adjust_pointer_closure());
+  Management::oops_do(adjust_pointer_closure());
+  JvmtiExport::oops_do(adjust_pointer_closure());
   // SO_AllClasses
-  SystemDictionary::oops_do(adjust_root_pointer_closure());
-  ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true);
-  //CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure());
+  SystemDictionary::oops_do(adjust_pointer_closure());
+  ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true);
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
   // Global (weak) JNI handles
-  JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure());
+  JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
 
   CodeCache::oops_do(adjust_pointer_closure());
-  StringTable::oops_do(adjust_root_pointer_closure());
-  ref_processor()->weak_oops_do(adjust_root_pointer_closure());
-  PSScavenge::reference_processor()->weak_oops_do(adjust_root_pointer_closure());
+  StringTable::oops_do(adjust_pointer_closure());
+  ref_processor()->weak_oops_do(adjust_pointer_closure());
+  PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
 
   adjust_marks();
 
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.hpp	Thu May 16 11:47:51 2013 +0100
@@ -44,7 +44,6 @@
   static KlassClosure* follow_klass_closure() { return &MarkSweep::follow_klass_closure; }
   static VoidClosure* follow_stack_closure() { return (VoidClosure*)&MarkSweep::follow_stack_closure; }
   static OopClosure* adjust_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_pointer_closure; }
-  static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&MarkSweep::adjust_root_pointer_closure; }
   static KlassClosure* adjust_klass_closure() { return &MarkSweep::adjust_klass_closure; }
   static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&MarkSweep::is_alive; }
 
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Thu May 16 11:47:51 2013 +0100
@@ -787,12 +787,11 @@
 void PSParallelCompact::KeepAliveClosure::do_oop(oop* p)       { PSParallelCompact::KeepAliveClosure::do_oop_work(p); }
 void PSParallelCompact::KeepAliveClosure::do_oop(narrowOop* p) { PSParallelCompact::KeepAliveClosure::do_oop_work(p); }
 
-PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_root_pointer_closure(true);
-PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure(false);
+PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure;
 PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure;
 
-void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p)       { adjust_pointer(p, _is_root); }
-void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); }
+void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p)       { adjust_pointer(p); }
+void PSParallelCompact::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); }
 
 void PSParallelCompact::FollowStackClosure::do_void() { _compaction_manager->follow_marking_stacks(); }
 
@@ -805,7 +804,7 @@
   klass->oops_do(_mark_and_push_closure);
 }
 void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) {
-  klass->oops_do(&PSParallelCompact::_adjust_root_pointer_closure);
+  klass->oops_do(&PSParallelCompact::_adjust_pointer_closure);
 }
 
 void PSParallelCompact::post_initialize() {
@@ -892,7 +891,7 @@
     _heap_used      = heap->used();
     _young_gen_used = heap->young_gen()->used_in_bytes();
     _old_gen_used   = heap->old_gen()->used_in_bytes();
-    _metadata_used  = MetaspaceAux::used_in_bytes();
+    _metadata_used  = MetaspaceAux::allocated_used_bytes();
   };
 
   size_t heap_used() const      { return _heap_used; }
@@ -967,8 +966,7 @@
 
   if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyBeforeGC:");
-    Universe::verify();
+    Universe::verify(" VerifyBeforeGC:");
   }
 
   // Verify object start arrays
@@ -1027,6 +1025,7 @@
 
   // Delete metaspaces for unloaded class loaders and clean up loader_data graph
   ClassLoaderDataGraph::purge();
+  MetaspaceAux::verify_metrics();
 
   Threads::gc_epilogue();
   CodeCache::gc_epilogue();
@@ -2168,8 +2167,7 @@
 
   if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyAfterGC:");
-    Universe::verify();
+    Universe::verify(" VerifyAfterGC:");
   }
 
   // Re-verify object start arrays
@@ -2356,22 +2354,24 @@
   }
 
   TraceTime tm_c("class unloading", print_phases(), true, gclog_or_tty);
+
+  // This is the point where the entire marking should have completed.
+  assert(cm->marking_stacks_empty(), "Marking should have completed");
+
   // Follow system dictionary roots and unload classes.
   bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
 
-  // Follow code cache roots.
+  // Unload nmethods.
   CodeCache::do_unloading(is_alive_closure(), purged_class);
-  cm->follow_marking_stacks(); // Flush marking stack.
-
-  // Update subklass/sibling/implementor links of live klasses
+
+  // Prune dead klasses from subklass/sibling/implementor lists.
   Klass::clean_weak_klass_links(is_alive_closure());
 
-  // Visit interned string tables and delete unmarked oops
+  // Delete entries for dead interned strings.
   StringTable::unlink(is_alive_closure());
+
   // Clean up unreferenced symbols in symbol table.
   SymbolTable::unlink();
-
-  assert(cm->marking_stacks_empty(), "marking stacks should be empty");
 }
 
 void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) {
@@ -2398,7 +2398,7 @@
 
 void PSParallelCompact::adjust_class_loader(ParCompactionManager* cm,
                                             ClassLoaderData* cld) {
-  cld->oops_do(PSParallelCompact::adjust_root_pointer_closure(),
+  cld->oops_do(PSParallelCompact::adjust_pointer_closure(),
                PSParallelCompact::adjust_klass_closure(),
                true);
 }
@@ -2419,32 +2419,31 @@
   ClassLoaderDataGraph::clear_claimed_marks();
 
   // General strong roots.
-  Universe::oops_do(adjust_root_pointer_closure());
-  JNIHandles::oops_do(adjust_root_pointer_closure());   // Global (strong) JNI handles
-  CLDToOopClosure adjust_from_cld(adjust_root_pointer_closure());
-  Threads::oops_do(adjust_root_pointer_closure(), &adjust_from_cld, NULL);
-  ObjectSynchronizer::oops_do(adjust_root_pointer_closure());
-  FlatProfiler::oops_do(adjust_root_pointer_closure());
-  Management::oops_do(adjust_root_pointer_closure());
-  JvmtiExport::oops_do(adjust_root_pointer_closure());
+  Universe::oops_do(adjust_pointer_closure());
+  JNIHandles::oops_do(adjust_pointer_closure());   // Global (strong) JNI handles
+  CLDToOopClosure adjust_from_cld(adjust_pointer_closure());
+  Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL);
+  ObjectSynchronizer::oops_do(adjust_pointer_closure());
+  FlatProfiler::oops_do(adjust_pointer_closure());
+  Management::oops_do(adjust_pointer_closure());
+  JvmtiExport::oops_do(adjust_pointer_closure());
   // SO_AllClasses
-  SystemDictionary::oops_do(adjust_root_pointer_closure());
-  ClassLoaderDataGraph::oops_do(adjust_root_pointer_closure(), adjust_klass_closure(), true);
+  SystemDictionary::oops_do(adjust_pointer_closure());
+  ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true);
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
   // Global (weak) JNI handles
-  JNIHandles::weak_oops_do(&always_true, adjust_root_pointer_closure());
+  JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
 
   CodeCache::oops_do(adjust_pointer_closure());
-  StringTable::oops_do(adjust_root_pointer_closure());
-  ref_processor()->weak_oops_do(adjust_root_pointer_closure());
+  StringTable::oops_do(adjust_pointer_closure());
+  ref_processor()->weak_oops_do(adjust_pointer_closure());
   // Roots were visited so references into the young gen in roots
   // may have been scanned.  Process them also.
   // Should the reference processor have a span that excludes
   // young gen objects?
-  PSScavenge::reference_processor()->weak_oops_do(
-                                              adjust_root_pointer_closure());
+  PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
 }
 
 void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q,
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp	Thu May 16 11:47:51 2013 +0100
@@ -799,16 +799,6 @@
     virtual void do_oop(narrowOop* p);
   };
 
-  // Current unused
-  class FollowRootClosure: public OopsInGenClosure {
-   private:
-    ParCompactionManager* _compaction_manager;
-   public:
-    FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
-    virtual void do_oop(oop* p);
-    virtual void do_oop(narrowOop* p);
- };
-
   class FollowStackClosure: public VoidClosure {
    private:
     ParCompactionManager* _compaction_manager;
@@ -818,10 +808,7 @@
   };
 
   class AdjustPointerClosure: public OopClosure {
-   private:
-    bool _is_root;
    public:
-    AdjustPointerClosure(bool is_root) : _is_root(is_root) { }
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
     // do not walk from thread stacks to the code cache on this phase
@@ -838,7 +825,6 @@
   friend class AdjustPointerClosure;
   friend class AdjustKlassClosure;
   friend class FollowKlassClosure;
-  friend class FollowRootClosure;
   friend class InstanceClassLoaderKlass;
   friend class RefProcTaskProxy;
 
@@ -853,7 +839,6 @@
   static IsAliveClosure       _is_alive_closure;
   static SpaceInfo            _space_info[last_space_id];
   static bool                 _print_phases;
-  static AdjustPointerClosure _adjust_root_pointer_closure;
   static AdjustPointerClosure _adjust_pointer_closure;
   static AdjustKlassClosure   _adjust_klass_closure;
 
@@ -889,9 +874,6 @@
   static void marking_phase(ParCompactionManager* cm,
                             bool maximum_heap_compaction);
 
-  template <class T> static inline void adjust_pointer(T* p, bool is_root);
-  static void adjust_root_pointer(oop* p) { adjust_pointer(p, true); }
-
   template <class T>
   static inline void follow_root(ParCompactionManager* cm, T* p);
 
@@ -1046,7 +1028,6 @@
 
   // Closure accessors
   static OopClosure* adjust_pointer_closure()      { return (OopClosure*)&_adjust_pointer_closure; }
-  static OopClosure* adjust_root_pointer_closure() { return (OopClosure*)&_adjust_root_pointer_closure; }
   static KlassClosure* adjust_klass_closure()      { return (KlassClosure*)&_adjust_klass_closure; }
   static BoolObjectClosure* is_alive_closure()     { return (BoolObjectClosure*)&_is_alive_closure; }
 
@@ -1067,6 +1048,7 @@
   // Check mark and maybe push on marking stack
   template <class T> static inline void mark_and_push(ParCompactionManager* cm,
                                                       T* p);
+  template <class T> static inline void adjust_pointer(T* p);
 
   static void follow_klass(ParCompactionManager* cm, Klass* klass);
   static void adjust_klass(ParCompactionManager* cm, Klass* klass);
@@ -1151,9 +1133,6 @@
   static ParMarkBitMap* mark_bitmap() { return &_mark_bitmap; }
   static ParallelCompactData& summary_data() { return _summary_data; }
 
-  static inline void adjust_pointer(oop* p)       { adjust_pointer(p, false); }
-  static inline void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); }
-
   // Reference Processing
   static ReferenceProcessor* const ref_processor() { return _ref_processor; }
 
@@ -1230,7 +1209,7 @@
 }
 
 template <class T>
-inline void PSParallelCompact::adjust_pointer(T* p, bool isroot) {
+inline void PSParallelCompact::adjust_pointer(T* p) {
   T heap_oop = oopDesc::load_heap_oop(p);
   if (!oopDesc::is_null(heap_oop)) {
     oop obj     = oopDesc::decode_heap_oop_not_null(heap_oop);
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp	Thu May 16 11:47:51 2013 +0100
@@ -314,8 +314,7 @@
 
   if (VerifyBeforeGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyBeforeGC:");
-    Universe::verify();
+    Universe::verify(" VerifyBeforeGC:");
   }
 
   {
@@ -638,8 +637,7 @@
 
   if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
     HandleMark hm;  // Discard invalid handles created during verification
-    gclog_or_tty->print(" VerifyAfterGC:");
-    Universe::verify();
+    Universe::verify(" VerifyAfterGC:");
   }
 
   heap->print_heap_after_gc();
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.cpp	Thu May 16 11:47:51 2013 +0100
@@ -81,7 +81,7 @@
 }
 
 void MarkSweep::adjust_class_loader(ClassLoaderData* cld) {
-  cld->oops_do(&MarkSweep::adjust_root_pointer_closure, &MarkSweep::adjust_klass_closure, true);
+  cld->oops_do(&MarkSweep::adjust_pointer_closure, &MarkSweep::adjust_klass_closure, true);
 }
 
 
@@ -121,11 +121,10 @@
   }
 }
 
-MarkSweep::AdjustPointerClosure MarkSweep::adjust_root_pointer_closure(true);
-MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure(false);
+MarkSweep::AdjustPointerClosure MarkSweep::adjust_pointer_closure;
 
-void MarkSweep::AdjustPointerClosure::do_oop(oop* p)       { adjust_pointer(p, _is_root); }
-void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p, _is_root); }
+void MarkSweep::AdjustPointerClosure::do_oop(oop* p)       { adjust_pointer(p); }
+void MarkSweep::AdjustPointerClosure::do_oop(narrowOop* p) { adjust_pointer(p); }
 
 void MarkSweep::adjust_marks() {
   assert( _preserved_oop_stack.size() == _preserved_mark_stack.size(),
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.hpp	Thu May 16 11:47:51 2013 +0100
@@ -80,10 +80,7 @@
   };
 
   class AdjustPointerClosure: public OopsInGenClosure {
-   private:
-    bool _is_root;
    public:
-    AdjustPointerClosure(bool is_root) : _is_root(is_root) {}
     virtual void do_oop(oop* p);
     virtual void do_oop(narrowOop* p);
   };
@@ -146,7 +143,6 @@
   static MarkAndPushClosure   mark_and_push_closure;
   static FollowKlassClosure   follow_klass_closure;
   static FollowStackClosure   follow_stack_closure;
-  static AdjustPointerClosure adjust_root_pointer_closure;
   static AdjustPointerClosure adjust_pointer_closure;
   static AdjustKlassClosure   adjust_klass_closure;
 
@@ -179,12 +175,7 @@
   static void adjust_marks();   // Adjust the pointers in the preserved marks table
   static void restore_marks();  // Restore the marks that we saved in preserve_mark
 
-  template <class T> static inline void adjust_pointer(T* p, bool isroot);
-
-  static void adjust_root_pointer(oop* p)  { adjust_pointer(p, true); }
-  static void adjust_pointer(oop* p)       { adjust_pointer(p, false); }
-  static void adjust_pointer(narrowOop* p) { adjust_pointer(p, false); }
-
+  template <class T> static inline void adjust_pointer(T* p);
 };
 
 class PreservedMark VALUE_OBJ_CLASS_SPEC {
--- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp	Thu May 16 11:47:51 2013 +0100
@@ -76,7 +76,7 @@
   _objarray_stack.push(task);
 }
 
-template <class T> inline void MarkSweep::adjust_pointer(T* p, bool isroot) {
+template <class T> inline void MarkSweep::adjust_pointer(T* p) {
   T heap_oop = oopDesc::load_heap_oop(p);
   if (!oopDesc::is_null(heap_oop)) {
     oop obj     = oopDesc::decode_heap_oop_not_null(heap_oop);
--- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp	Thu May 16 11:47:51 2013 +0100
@@ -225,7 +225,10 @@
         gclog_or_tty->print_cr("\nCMS full GC for Metaspace");
       }
       heap->collect_as_vm_thread(GCCause::_metadata_GC_threshold);
-      _result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
+      // After a GC try to allocate without expanding.  Could fail
+      // and expansion will be tried below.
+      _result =
+        _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
     }
     if (_result == NULL && !UseConcMarkSweepGC /* CMS already tried */) {
       // If still failing, allow the Metaspace to expand.
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp	Thu May 16 11:47:51 2013 +0100
@@ -32,6 +32,7 @@
 #include "interpreter/interpreterRuntime.hpp"
 #include "memory/cardTableModRefBS.hpp"
 #include "memory/resourceArea.hpp"
+#include "oops/methodCounters.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -304,11 +305,12 @@
 
 
 #define METHOD istate->method()
-#define INVOCATION_COUNT METHOD->invocation_counter()
-#define BACKEDGE_COUNT METHOD->backedge_counter()
-
-
-#define INCR_INVOCATION_COUNT INVOCATION_COUNT->increment()
+#define GET_METHOD_COUNTERS(res)    \
+  res = METHOD->method_counters();  \
+  if (res == NULL) {                \
+    CALL_VM(res = InterpreterRuntime::build_method_counters(THREAD, METHOD), handle_exception); \
+  }
+
 #define OSR_REQUEST(res, branch_pc) \
             CALL_VM(res=InterpreterRuntime::frequency_counter_overflow(THREAD, branch_pc), handle_exception);
 /*
@@ -325,10 +327,12 @@
 
 #define DO_BACKEDGE_CHECKS(skip, branch_pc)                                                         \
     if ((skip) <= 0) {                                                                              \
+      MethodCounters* mcs;                                                                          \
+      GET_METHOD_COUNTERS(mcs);                                                                     \
       if (UseLoopCounter) {                                                                         \
         bool do_OSR = UseOnStackReplacement;                                                        \
-        BACKEDGE_COUNT->increment();                                                                \
-        if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit();                             \
+        mcs->backedge_counter()->increment();                                                       \
+        if (do_OSR) do_OSR = mcs->backedge_counter()->reached_InvocationLimit();                    \
         if (do_OSR) {                                                                               \
           nmethod*  osr_nmethod;                                                                    \
           OSR_REQUEST(osr_nmethod, branch_pc);                                                      \
@@ -341,7 +345,7 @@
           }                                                                                         \
         }                                                                                           \
       }  /* UseCompiler ... */                                                                      \
-      INCR_INVOCATION_COUNT;                                                                        \
+      mcs->invocation_counter()->increment();                                                       \
       SAFEPOINT;                                                                                    \
     }
 
@@ -618,11 +622,13 @@
       // count invocations
       assert(initialized, "Interpreter not initialized");
       if (_compiling) {
+        MethodCounters* mcs;
+        GET_METHOD_COUNTERS(mcs);
         if (ProfileInterpreter) {
-          METHOD->increment_interpreter_invocation_count();
+          METHOD->increment_interpreter_invocation_count(THREAD);
         }
-        INCR_INVOCATION_COUNT;
-        if (INVOCATION_COUNT->reached_InvocationLimit()) {
+        mcs->invocation_counter()->increment();
+        if (mcs->invocation_counter()->reached_InvocationLimit()) {
             CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception);
 
             // We no longer retry on a counter overflow
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1052,7 +1052,7 @@
     return;
   }
   if (set_handler_blob() == NULL) {
-    vm_exit_out_of_memory(blob_size, "native signature handlers");
+    vm_exit_out_of_memory(blob_size, OOM_MALLOC_ERROR, "native signature handlers");
   }
 
   BufferBlob* bb = BufferBlob::create("Signature Handler Temp Buffer",
--- a/hotspot/src/share/vm/memory/allocation.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/allocation.cpp	Thu May 16 11:47:51 2013 +0100
@@ -259,7 +259,7 @@
     }
     if (p == NULL) p = os::malloc(bytes, mtChunk, CURRENT_PC);
     if (p == NULL)
-      vm_exit_out_of_memory(bytes, "ChunkPool::allocate");
+      vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "ChunkPool::allocate");
 
     return p;
   }
@@ -371,7 +371,7 @@
    default: {
      void *p =  os::malloc(bytes, mtChunk, CALLER_PC);
      if (p == NULL)
-       vm_exit_out_of_memory(bytes, "Chunk::new");
+       vm_exit_out_of_memory(bytes, OOM_MALLOC_ERROR, "Chunk::new");
      return p;
    }
   }
@@ -531,7 +531,7 @@
 }
 
 void Arena::signal_out_of_memory(size_t sz, const char* whence) const {
-  vm_exit_out_of_memory(sz, whence);
+  vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, whence);
 }
 
 // Grow a new Chunk
--- a/hotspot/src/share/vm/memory/allocation.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/allocation.hpp	Thu May 16 11:47:51 2013 +0100
@@ -539,6 +539,9 @@
 #define NEW_RESOURCE_ARRAY(type, size)\
   (type*) resource_allocate_bytes((size) * sizeof(type))
 
+#define NEW_RESOURCE_ARRAY_RETURN_NULL(type, size)\
+  (type*) resource_allocate_bytes((size) * sizeof(type), AllocFailStrategy::RETURN_NULL)
+
 #define NEW_RESOURCE_ARRAY_IN_THREAD(thread, type, size)\
   (type*) resource_allocate_bytes(thread, (size) * sizeof(type))
 
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp	Thu May 16 11:47:51 2013 +0100
@@ -58,7 +58,9 @@
   #ifdef ASSERT
   if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);
   #endif
-  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "AllocateHeap");
+  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
+    vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap");
+  }
   return p;
 }
 
@@ -68,7 +70,9 @@
   #ifdef ASSERT
   if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p);
   #endif
-  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) vm_exit_out_of_memory(size, "ReallocateHeap");
+  if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
+    vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "ReallocateHeap");
+  }
   return p;
 }
 
@@ -128,14 +132,14 @@
   int alignment = os::vm_allocation_granularity();
   _size = align_size_up(_size, alignment);
 
-  _addr = os::reserve_memory(_size, NULL, alignment);
+  _addr = os::reserve_memory(_size, NULL, alignment, F);
   if (_addr == NULL) {
-    vm_exit_out_of_memory(_size, "Allocator (reserve)");
+    vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (reserve)");
   }
 
   bool success = os::commit_memory(_addr, _size, false /* executable */);
   if (!success) {
-    vm_exit_out_of_memory(_size, "Allocator (commit)");
+    vm_exit_out_of_memory(_size, OOM_MMAP_ERROR, "Allocator (commit)");
   }
 
   return (E*)_addr;
--- a/hotspot/src/share/vm/memory/blockOffsetTable.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/blockOffsetTable.cpp	Thu May 16 11:47:51 2013 +0100
@@ -80,7 +80,7 @@
     assert(delta > 0, "just checking");
     if (!_vs.expand_by(delta)) {
       // Do better than this for Merlin
-      vm_exit_out_of_memory(delta, "offset table expansion");
+      vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");
     }
     assert(_vs.high() == high + delta, "invalid expansion");
   } else {
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp	Thu May 16 11:47:51 2013 +0100
@@ -116,7 +116,7 @@
   _guard_region = MemRegion((HeapWord*)guard_page, _page_size);
   if (!os::commit_memory((char*)guard_page, _page_size, _page_size)) {
     // Do better than this for Merlin
-    vm_exit_out_of_memory(_page_size, "card table last card");
+    vm_exit_out_of_memory(_page_size, OOM_MMAP_ERROR, "card table last card");
   }
 
   *guard_card = last_card;
@@ -292,7 +292,7 @@
       if (!os::commit_memory((char*)new_committed.start(),
                              new_committed.byte_size(), _page_size)) {
         // Do better than this for Merlin
-        vm_exit_out_of_memory(new_committed.byte_size(),
+        vm_exit_out_of_memory(new_committed.byte_size(), OOM_MMAP_ERROR,
                 "card table expansion");
       }
     // Use new_end_aligned (as opposed to new_end_for_commit) because
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp	Thu May 16 11:47:51 2013 +0100
@@ -48,6 +48,17 @@
 // CollectorPolicy methods.
 
 void CollectorPolicy::initialize_flags() {
+  assert(max_alignment() >= min_alignment(),
+      err_msg("max_alignment: " SIZE_FORMAT " less than min_alignment: " SIZE_FORMAT,
+          max_alignment(), min_alignment()));
+  assert(max_alignment() % min_alignment() == 0,
+      err_msg("max_alignment: " SIZE_FORMAT " not aligned by min_alignment: " SIZE_FORMAT,
+          max_alignment(), min_alignment()));
+
+  if (MaxHeapSize < InitialHeapSize) {
+    vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified");
+  }
+
   if (MetaspaceSize > MaxMetaspaceSize) {
     MaxMetaspaceSize = MetaspaceSize;
   }
@@ -71,21 +82,9 @@
 }
 
 void CollectorPolicy::initialize_size_info() {
-  // User inputs from -mx and ms are aligned
-  set_initial_heap_byte_size(InitialHeapSize);
-  if (initial_heap_byte_size() == 0) {
-    set_initial_heap_byte_size(NewSize + OldSize);
-  }
-  set_initial_heap_byte_size(align_size_up(_initial_heap_byte_size,
-                                           min_alignment()));
-
-  set_min_heap_byte_size(Arguments::min_heap_size());
-  if (min_heap_byte_size() == 0) {
-    set_min_heap_byte_size(NewSize + OldSize);
-  }
-  set_min_heap_byte_size(align_size_up(_min_heap_byte_size,
-                                       min_alignment()));
-
+  // User inputs from -mx and ms must be aligned
+  set_min_heap_byte_size(align_size_up(Arguments::min_heap_size(), min_alignment()));
+  set_initial_heap_byte_size(align_size_up(InitialHeapSize, min_alignment()));
   set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment()));
 
   // Check heap parameter properties
@@ -201,9 +200,6 @@
   // All sizes must be multiples of the generation granularity.
   set_min_alignment((uintx) Generation::GenGrain);
   set_max_alignment(compute_max_alignment());
-  assert(max_alignment() >= min_alignment() &&
-         max_alignment() % min_alignment() == 0,
-         "invalid alignment constraints");
 
   CollectorPolicy::initialize_flags();
 
@@ -233,9 +229,6 @@
   GenCollectorPolicy::initialize_flags();
 
   OldSize = align_size_down(OldSize, min_alignment());
-  if (NewSize + OldSize > MaxHeapSize) {
-    MaxHeapSize = NewSize + OldSize;
-  }
 
   if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(NewSize)) {
     // NewRatio will be used later to set the young generation size so we use
@@ -250,6 +243,27 @@
   }
   MaxHeapSize = align_size_up(MaxHeapSize, max_alignment());
 
+  // adjust max heap size if necessary
+  if (NewSize + OldSize > MaxHeapSize) {
+    if (FLAG_IS_CMDLINE(MaxHeapSize)) {
+      // somebody set a maximum heap size with the intention that we should not
+      // exceed it. Adjust New/OldSize as necessary.
+      uintx calculated_size = NewSize + OldSize;
+      double shrink_factor = (double) MaxHeapSize / calculated_size;
+      // align
+      NewSize = align_size_down((uintx) (NewSize * shrink_factor), min_alignment());
+      // OldSize is already aligned because above we aligned MaxHeapSize to
+      // max_alignment(), and we just made sure that NewSize is aligned to
+      // min_alignment(). In initialize_flags() we verified that max_alignment()
+      // is a multiple of min_alignment().
+      OldSize = MaxHeapSize - NewSize;
+    } else {
+      MaxHeapSize = NewSize + OldSize;
+    }
+  }
+  // need to do this again
+  MaxHeapSize = align_size_up(MaxHeapSize, max_alignment());
+
   always_do_update_barrier = UseConcMarkSweepGC;
 
   // Check validity of heap flags
--- a/hotspot/src/share/vm/memory/filemap.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/filemap.cpp	Thu May 16 11:47:51 2013 +0100
@@ -238,8 +238,8 @@
 
 void FileMapInfo::write_space(int i, Metaspace* space, bool read_only) {
   align_file_position();
-  size_t used = space->used_words(Metaspace::NonClassType) * BytesPerWord;
-  size_t capacity = space->capacity_words(Metaspace::NonClassType) * BytesPerWord;
+  size_t used = space->used_bytes_slow(Metaspace::NonClassType);
+  size_t capacity = space->capacity_bytes_slow(Metaspace::NonClassType);
   struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[i];
   write_region(i, (char*)space->bottom(), used, capacity, read_only, false);
 }
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp	Thu May 16 11:47:51 2013 +0100
@@ -377,7 +377,7 @@
 
   ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
 
-  const size_t metadata_prev_used = MetaspaceAux::used_in_bytes();
+  const size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
 
   print_heap_before_gc();
 
@@ -447,8 +447,7 @@
             prepare_for_verify();
             prepared_for_verification = true;
           }
-          gclog_or_tty->print(" VerifyBeforeGC:");
-          Universe::verify();
+          Universe::verify(" VerifyBeforeGC:");
         }
         COMPILER2_PRESENT(DerivedPointerTable::clear());
 
@@ -519,8 +518,7 @@
         if (VerifyAfterGC && i >= VerifyGCLevel &&
             total_collections() >= VerifyGCStartAt) {
           HandleMark hm;  // Discard invalid handles created during verification
-          gclog_or_tty->print(" VerifyAfterGC:");
-          Universe::verify();
+          Universe::verify(" VerifyAfterGC:");
         }
 
         if (PrintGCDetails) {
@@ -556,6 +554,7 @@
     if (complete) {
       // Delete metaspaces for unloaded class loaders and clean up loader_data graph
       ClassLoaderDataGraph::purge();
+      MetaspaceAux::verify_metrics();
       // Resize the metaspace capacity after full collections
       MetaspaceGC::compute_new_size();
       update_full_collections_completed();
@@ -633,9 +632,8 @@
 }
 
 void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure,
-                                              CodeBlobClosure* code_roots,
-                                              OopClosure* non_root_closure) {
-  SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure);
+                                              CodeBlobClosure* code_roots) {
+  SharedHeap::process_weak_roots(root_closure, code_roots);
   // "Local" "weak" refs
   for (int i = 0; i < _n_gens; i++) {
     _gens[i]->ref_processor()->weak_oops_do(root_closure);
--- a/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.hpp	Thu May 16 11:47:51 2013 +0100
@@ -432,8 +432,7 @@
   // JNI weak roots, the code cache, system dictionary, symbol table,
   // string table, and referents of reachable weak refs.
   void gen_process_weak_roots(OopClosure* root_closure,
-                              CodeBlobClosure* code_roots,
-                              OopClosure* non_root_closure);
+                              CodeBlobClosure* code_roots);
 
   // Set the saved marks of generations, if that makes sense.
   // In particular, if any generation might iterate over the oops
--- a/hotspot/src/share/vm/memory/genMarkSweep.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/genMarkSweep.cpp	Thu May 16 11:47:51 2013 +0100
@@ -223,23 +223,23 @@
       &is_alive, &keep_alive, &follow_stack_closure, NULL);
   }
 
-  // Follow system dictionary roots and unload classes
+  // This is the point where the entire marking should have completed.
+  assert(_marking_stack.is_empty(), "Marking should have completed");
+
+  // Unload classes and purge the SystemDictionary.
   bool purged_class = SystemDictionary::do_unloading(&is_alive);
 
-  // Follow code cache roots
+  // Unload nmethods.
   CodeCache::do_unloading(&is_alive, purged_class);
-  follow_stack(); // Flush marking stack
 
-  // Update subklass/sibling/implementor links of live klasses
+  // Prune dead klasses from subklass/sibling/implementor lists.
   Klass::clean_weak_klass_links(&is_alive);
-  assert(_marking_stack.is_empty(), "just drained");
 
-  // Visit interned string tables and delete unmarked oops
+  // Delete entries for dead interned strings.
   StringTable::unlink(&is_alive);
+
   // Clean up unreferenced symbols in symbol table.
   SymbolTable::unlink();
-
-  assert(_marking_stack.is_empty(), "stack should be empty by now");
 }
 
 
@@ -282,11 +282,10 @@
   // Need new claim bits for the pointer adjustment tracing.
   ClassLoaderDataGraph::clear_claimed_marks();
 
-  // Because the two closures below are created statically, cannot
+  // Because the closure below is created statically, we cannot
   // use OopsInGenClosure constructor which takes a generation,
   // as the Universe has not been created when the static constructors
   // are run.
-  adjust_root_pointer_closure.set_orig_generation(gch->get_gen(level));
   adjust_pointer_closure.set_orig_generation(gch->get_gen(level));
 
   gch->gen_process_strong_roots(level,
@@ -294,18 +293,17 @@
                                 true,  // activate StrongRootsScope
                                 false, // not scavenging
                                 SharedHeap::SO_AllClasses,
-                                &adjust_root_pointer_closure,
+                                &adjust_pointer_closure,
                                 false, // do not walk code
-                                &adjust_root_pointer_closure,
+                                &adjust_pointer_closure,
                                 &adjust_klass_closure);
 
   // Now adjust pointers in remaining weak roots.  (All of which should
   // have been cleared if they pointed to non-surviving objects.)
   CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure,
                                                    /*do_marking=*/ false);
-  gch->gen_process_weak_roots(&adjust_root_pointer_closure,
-                              &adjust_code_pointer_closure,
-                              &adjust_pointer_closure);
+  gch->gen_process_weak_roots(&adjust_pointer_closure,
+                              &adjust_code_pointer_closure);
 
   adjust_marks();
   GenAdjustPointersClosure blk;
--- a/hotspot/src/share/vm/memory/metachunk.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metachunk.cpp	Thu May 16 11:47:51 2013 +0100
@@ -28,6 +28,7 @@
 #include "utilities/copy.hpp"
 #include "utilities/debug.hpp"
 
+class VirtualSpaceNode;
 //
 // Future modification
 //
@@ -45,27 +46,30 @@
 
 // Metachunk methods
 
-Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) {
-  // Set bottom, top, and end.  Allow space for the Metachunk itself
-  Metachunk* chunk = (Metachunk*) ptr;
-
-  MetaWord* chunk_bottom = ptr + _overhead;
-  chunk->set_bottom(ptr);
-  chunk->set_top(chunk_bottom);
-  MetaWord* chunk_end = ptr + word_size;
-  assert(chunk_end > chunk_bottom, "Chunk must be too small");
-  chunk->set_end(chunk_end);
-  chunk->set_next(NULL);
-  chunk->set_prev(NULL);
-  chunk->set_word_size(word_size);
+Metachunk::Metachunk(size_t word_size,
+                     VirtualSpaceNode* container) :
+    _word_size(word_size),
+    _bottom(NULL),
+    _end(NULL),
+    _top(NULL),
+    _next(NULL),
+    _prev(NULL),
+    _container(container)
+{
+  _bottom = (MetaWord*)this;
+  _top = (MetaWord*)this + _overhead;
+  _end = (MetaWord*)this + word_size;
 #ifdef ASSERT
-  size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord));
-  Copy::fill_to_words((HeapWord*) chunk_bottom, data_word_size, metadata_chunk_initialize);
+  set_is_free(false);
+  size_t data_word_size = pointer_delta(end(),
+                                        top(),
+                                        sizeof(MetaWord));
+  Copy::fill_to_words((HeapWord*) top(),
+                      data_word_size,
+                      metadata_chunk_initialize);
 #endif
-  return chunk;
 }
 
-
 MetaWord* Metachunk::allocate(size_t word_size) {
   MetaWord* result = NULL;
   // If available, bump the pointer to allocate.
--- a/hotspot/src/share/vm/memory/metachunk.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metachunk.hpp	Thu May 16 11:47:51 2013 +0100
@@ -41,10 +41,13 @@
 //            |              |              |        |
 //            +--------------+ <- bottom ---+     ---+
 
+class VirtualSpaceNode;
+
 class Metachunk VALUE_OBJ_CLASS_SPEC {
   // link to support lists of chunks
   Metachunk* _next;
   Metachunk* _prev;
+  VirtualSpaceNode* _container;
 
   MetaWord* _bottom;
   MetaWord* _end;
@@ -61,29 +64,20 @@
   // the space.
   static size_t _overhead;
 
-  void set_bottom(MetaWord* v) { _bottom = v; }
-  void set_end(MetaWord* v) { _end = v; }
-  void set_top(MetaWord* v) { _top = v; }
-  void set_word_size(size_t v) { _word_size = v; }
  public:
-#ifdef ASSERT
-  Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false),
-    _next(NULL), _prev(NULL) {}
-#else
-  Metachunk() : _bottom(NULL), _end(NULL), _top(NULL),
-    _next(NULL), _prev(NULL) {}
-#endif
+  Metachunk(size_t word_size , VirtualSpaceNode* container);
 
   // Used to add a Metachunk to a list of Metachunks
   void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");}
   void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");}
+  void set_container(VirtualSpaceNode* v) { _container = v; }
 
   MetaWord* allocate(size_t word_size);
-  static Metachunk* initialize(MetaWord* ptr, size_t word_size);
 
   // Accessors
   Metachunk* next() const { return _next; }
   Metachunk* prev() const { return _prev; }
+  VirtualSpaceNode* container() const { return _container; }
   MetaWord* bottom() const { return _bottom; }
   MetaWord* end() const { return _end; }
   MetaWord* top() const { return _top; }
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Thu May 16 11:47:51 2013 +0100
@@ -47,7 +47,6 @@
 // the free chunk lists
 const bool metaspace_slow_verify = false;
 
-
 // Parameters for stress mode testing
 const uint metadata_deallocate_a_lot_block = 10;
 const uint metadata_deallocate_a_lock_chunk = 3;
@@ -112,6 +111,7 @@
 class ChunkManager VALUE_OBJ_CLASS_SPEC {
 
   // Free list of chunks of different sizes.
+  //   SpecializedChunk
   //   SmallChunk
   //   MediumChunk
   //   HumongousChunk
@@ -165,6 +165,10 @@
   // for special, small, medium, and humongous chunks.
   static ChunkIndex list_index(size_t size);
 
+  // Remove the chunk from its freelist.  It is
+  // expected to be on one of the _free_chunks[] lists.
+  void remove_chunk(Metachunk* chunk);
+
   // Add the simple linked list of chunks to the freelist of chunks
   // of type index.
   void return_chunks(ChunkIndex index, Metachunk* chunks);
@@ -215,7 +219,6 @@
   void print_on(outputStream* st);
 };
 
-
 // Used to manage the free list of Metablocks (a block corresponds
 // to the allocation of a quantum of metadata).
 class BlockFreelist VALUE_OBJ_CLASS_SPEC {
@@ -255,6 +258,8 @@
   ReservedSpace _rs;
   VirtualSpace _virtual_space;
   MetaWord* _top;
+  // count of chunks contained in this VirtualSpace
+  uintx _container_count;
 
   // Convenience functions for logical bottom and end
   MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); }
@@ -264,10 +269,19 @@
   char* low()  const { return virtual_space()->low(); }
   char* high() const { return virtual_space()->high(); }
 
+  // The first Metachunk will be allocated at the bottom of the
+  // VirtualSpace
+  Metachunk* first_chunk() { return (Metachunk*) bottom(); }
+
+  void inc_container_count();
+#ifdef ASSERT
+  uint container_count_slow();
+#endif
+
  public:
 
   VirtualSpaceNode(size_t byte_size);
-  VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs) {}
+  VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {}
   ~VirtualSpaceNode();
 
   // address of next available space in _virtual_space;
@@ -282,15 +296,22 @@
   MemRegion* reserved() { return &_reserved; }
   VirtualSpace* virtual_space() const { return (VirtualSpace*) &_virtual_space; }
 
-  // Returns true if "word_size" is available in the virtual space
+  // Returns true if "word_size" is available in the VirtualSpace
   bool is_available(size_t word_size) { return _top + word_size <= end(); }
 
   MetaWord* top() const { return _top; }
   void inc_top(size_t word_size) { _top += word_size; }
 
+  uintx container_count() { return _container_count; }
+  void dec_container_count();
+#ifdef ASSERT
+  void verify_container_count();
+#endif
+
   // used and capacity in this single entry in the list
   size_t used_words_in_vs() const;
   size_t capacity_words_in_vs() const;
+  size_t free_words_in_vs() const;
 
   bool initialize();
 
@@ -306,6 +327,10 @@
   bool expand_by(size_t words, bool pre_touch = false);
   bool shrink_by(size_t words);
 
+  // In preparation for deleting this node, remove all the chunks
+  // in the node from any freelist.
+  void purge(ChunkManager* chunk_manager);
+
 #ifdef ASSERT
   // Debug support
   static void verify_virtual_space_total();
@@ -317,7 +342,7 @@
 };
 
   // byte_size is the size of the associated virtualspace.
-VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0) {
+VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) {
   // align up to vm allocation granularity
   byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
 
@@ -341,6 +366,39 @@
   MemTracker::record_virtual_memory_type((address)_rs.base(), mtClass);
 }
 
+void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
+  Metachunk* chunk = first_chunk();
+  Metachunk* invalid_chunk = (Metachunk*) top();
+  while (chunk < invalid_chunk ) {
+    assert(chunk->is_free(), "Should be marked free");
+      MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+      chunk_manager->remove_chunk(chunk);
+      assert(chunk->next() == NULL &&
+             chunk->prev() == NULL,
+             "Was not removed from its list");
+      chunk = (Metachunk*) next;
+  }
+}
+
+#ifdef ASSERT
+uint VirtualSpaceNode::container_count_slow() {
+  uint count = 0;
+  Metachunk* chunk = first_chunk();
+  Metachunk* invalid_chunk = (Metachunk*) top();
+  while (chunk < invalid_chunk ) {
+    MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
+    // Don't count the chunks on the free lists.  Those are
+    // still part of the VirtualSpaceNode but not currently
+    // counted.
+    if (!chunk->is_free()) {
+      count++;
+    }
+    chunk = (Metachunk*) next;
+  }
+  return count;
+}
+#endif
+
 // List of VirtualSpaces for metadata allocation.
 // It has a  _next link for singly linked list and a MemRegion
 // for total space in the VirtualSpace.
@@ -390,6 +448,8 @@
   VirtualSpaceList(size_t word_size);
   VirtualSpaceList(ReservedSpace rs);
 
+  size_t free_bytes();
+
   Metachunk* get_new_chunk(size_t word_size,
                            size_t grow_chunks_by_words,
                            size_t medium_chunk_bunch);
@@ -410,14 +470,14 @@
   void initialize(size_t word_size);
 
   size_t virtual_space_total() { return _virtual_space_total; }
-  void inc_virtual_space_total(size_t v) {
-    Atomic::add_ptr(v, &_virtual_space_total);
-  }
-
-  size_t virtual_space_count() { return _virtual_space_count; }
-  void inc_virtual_space_count() {
-    Atomic::inc_ptr(&_virtual_space_count);
-  }
+
+  void inc_virtual_space_total(size_t v);
+  void dec_virtual_space_total(size_t v);
+  void inc_virtual_space_count();
+  void dec_virtual_space_count();
+
+  // Unlink empty VirtualSpaceNodes and free it.
+  void purge();
 
   // Used and capacity in the entire list of virtual spaces.
   // These are global values shared by all Metaspaces
@@ -520,7 +580,11 @@
   bool has_small_chunk_limit() { return !vs_list()->is_class(); }
 
   // Sum of all space in allocated chunks
-  size_t _allocation_total;
+  size_t _allocated_blocks_words;
+
+  // Sum of all allocated chunks
+  size_t _allocated_chunks_words;
+  size_t _allocated_chunks_count;
 
   // Free lists of blocks are per SpaceManager since they
   // are assumed to be in chunks in use by the SpaceManager
@@ -576,12 +640,27 @@
   size_t medium_chunk_size() { return (size_t) vs_list()->is_class() ? ClassMediumChunk : MediumChunk; }
   size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; }
 
-  size_t allocation_total() const { return _allocation_total; }
-  void inc_allocation_total(size_t v) { Atomic::add_ptr(v, &_allocation_total); }
+  size_t allocated_blocks_words() const { return _allocated_blocks_words; }
+  size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; }
+  size_t allocated_chunks_words() const { return _allocated_chunks_words; }
+  size_t allocated_chunks_count() const { return _allocated_chunks_count; }
+
   bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); }
 
   static Mutex* expand_lock() { return _expand_lock; }
 
+  // Increment the per Metaspace and global running sums for Metachunks
+  // by the given size.  This is used when a Metachunk to added to
+  // the in-use list.
+  void inc_size_metrics(size_t words);
+  // Increment the per Metaspace and global running sums Metablocks by the given
+  // size.  This is used when a Metablock is allocated.
+  void inc_used_metrics(size_t words);
+  // Delete the portion of the running sums for this SpaceManager. That is,
+  // the globals running sums for the Metachunks and Metablocks are
+  // decremented for all the Metachunks in-use by this SpaceManager.
+  void dec_total_from_size_metrics();
+
   // Set the sizes for the initial chunks.
   void get_initial_chunk_sizes(Metaspace::MetaspaceType type,
                                size_t* chunk_word_size,
@@ -627,7 +706,7 @@
   void verify_chunk_size(Metachunk* chunk);
   NOT_PRODUCT(void mangle_freed_chunks();)
 #ifdef ASSERT
-  void verify_allocation_total();
+  void verify_allocated_blocks_words();
 #endif
 };
 
@@ -641,6 +720,28 @@
             SpaceManager::_expand_lock_name,
             Mutex::_allow_vm_block_flag);
 
+void VirtualSpaceNode::inc_container_count() {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _container_count++;
+  assert(_container_count == container_count_slow(),
+         err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT
+                 "container_count_slow() " SIZE_FORMAT,
+                 _container_count, container_count_slow()));
+}
+
+void VirtualSpaceNode::dec_container_count() {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _container_count--;
+}
+
+#ifdef ASSERT
+void VirtualSpaceNode::verify_container_count() {
+  assert(_container_count == container_count_slow(),
+    err_msg("Inconsistency in countainer_count _container_count " SIZE_FORMAT
+            "container_count_slow() " SIZE_FORMAT, _container_count, container_count_slow()));
+}
+#endif
+
 // BlockFreelist methods
 
 BlockFreelist::BlockFreelist() : _dictionary(NULL) {}
@@ -701,6 +802,10 @@
 
 VirtualSpaceNode::~VirtualSpaceNode() {
   _rs.release();
+#ifdef ASSERT
+  size_t word_size = sizeof(*this) / BytesPerWord;
+  Copy::fill_to_words((HeapWord*) this, word_size, 0xf1f1f1f1);
+#endif
 }
 
 size_t VirtualSpaceNode::used_words_in_vs() const {
@@ -712,6 +817,9 @@
   return pointer_delta(end(), bottom(), sizeof(MetaWord));
 }
 
+size_t VirtualSpaceNode::free_words_in_vs() const {
+  return pointer_delta(end(), top(), sizeof(MetaWord));
+}
 
 // Allocates the chunk from the virtual space only.
 // This interface is also used internally for debugging.  Not all
@@ -733,8 +841,8 @@
   // Take the space  (bump top on the current virtual space).
   inc_top(chunk_word_size);
 
-  // Point the chunk at the space
-  Metachunk* result = Metachunk::initialize(chunk_limit, chunk_word_size);
+  // Initialize the chunk
+  Metachunk* result = ::new (chunk_limit) Metachunk(chunk_word_size, this);
   return result;
 }
 
@@ -762,9 +870,11 @@
 
 Metachunk* VirtualSpaceNode::get_chunk_vs(size_t chunk_word_size) {
   assert_lock_strong(SpaceManager::expand_lock());
-  Metachunk* result = NULL;
-
-  return take_from_committed(chunk_word_size);
+  Metachunk* result = take_from_committed(chunk_word_size);
+  if (result != NULL) {
+    inc_container_count();
+  }
+  return result;
 }
 
 Metachunk* VirtualSpaceNode::get_chunk_vs_with_expand(size_t chunk_word_size) {
@@ -843,6 +953,83 @@
   }
 }
 
+void VirtualSpaceList::inc_virtual_space_total(size_t v) {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _virtual_space_total = _virtual_space_total + v;
+}
+void VirtualSpaceList::dec_virtual_space_total(size_t v) {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _virtual_space_total = _virtual_space_total - v;
+}
+
+void VirtualSpaceList::inc_virtual_space_count() {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _virtual_space_count++;
+}
+void VirtualSpaceList::dec_virtual_space_count() {
+  assert_lock_strong(SpaceManager::expand_lock());
+  _virtual_space_count--;
+}
+
+void ChunkManager::remove_chunk(Metachunk* chunk) {
+  size_t word_size = chunk->word_size();
+  ChunkIndex index = list_index(word_size);
+  if (index != HumongousIndex) {
+    free_chunks(index)->remove_chunk(chunk);
+  } else {
+    humongous_dictionary()->remove_chunk(chunk);
+  }
+
+  // Chunk is being removed from the chunks free list.
+  dec_free_chunks_total(chunk->capacity_word_size());
+}
+
+// Walk the list of VirtualSpaceNodes and delete
+// nodes with a 0 container_count.  Remove Metachunks in
+// the node from their respective freelists.
+void VirtualSpaceList::purge() {
+  assert_lock_strong(SpaceManager::expand_lock());
+  // Don't use a VirtualSpaceListIterator because this
+  // list is being changed and a straightforward use of an iterator is not safe.
+  VirtualSpaceNode* purged_vsl = NULL;
+  VirtualSpaceNode* prev_vsl = virtual_space_list();
+  VirtualSpaceNode* next_vsl = prev_vsl;
+  while (next_vsl != NULL) {
+    VirtualSpaceNode* vsl = next_vsl;
+    next_vsl = vsl->next();
+    // Don't free the current virtual space since it will likely
+    // be needed soon.
+    if (vsl->container_count() == 0 && vsl != current_virtual_space()) {
+      // Unlink it from the list
+      if (prev_vsl == vsl) {
+        // This is the case of the current note being the first note.
+        assert(vsl == virtual_space_list(), "Expected to be the first note");
+        set_virtual_space_list(vsl->next());
+      } else {
+        prev_vsl->set_next(vsl->next());
+      }
+
+      vsl->purge(chunk_manager());
+      dec_virtual_space_total(vsl->reserved()->word_size());
+      dec_virtual_space_count();
+      purged_vsl = vsl;
+      delete vsl;
+    } else {
+      prev_vsl = vsl;
+    }
+  }
+#ifdef ASSERT
+  if (purged_vsl != NULL) {
+  // List should be stable enough to use an iterator here.
+  VirtualSpaceListIterator iter(virtual_space_list());
+    while (iter.repeat()) {
+      VirtualSpaceNode* vsl = iter.get_next();
+      assert(vsl != purged_vsl, "Purge of vsl failed");
+    }
+  }
+#endif
+}
+
 size_t VirtualSpaceList::used_words_sum() {
   size_t allocated_by_vs = 0;
   VirtualSpaceListIterator iter(virtual_space_list());
@@ -907,6 +1094,10 @@
   link_vs(class_entry, rs.size()/BytesPerWord);
 }
 
+size_t VirtualSpaceList::free_bytes() {
+  return virtual_space_list()->free_words_in_vs() * BytesPerWord;
+}
+
 // Allocate another meta virtual space and add it to the list.
 bool VirtualSpaceList::grow_vs(size_t vs_word_size) {
   assert_lock_strong(SpaceManager::expand_lock());
@@ -955,8 +1146,10 @@
   // Get a chunk from the chunk freelist
   Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words);
 
-  // Allocate a chunk out of the current virtual space.
-  if (next == NULL) {
+  if (next != NULL) {
+    next->container()->inc_container_count();
+  } else {
+    // Allocate a chunk out of the current virtual space.
     next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words);
   }
 
@@ -1045,9 +1238,9 @@
 //
 // After the GC the compute_new_size() for MetaspaceGC is called to
 // resize the capacity of the metaspaces.  The current implementation
-// is based on the flags MinMetaspaceFreeRatio and MaxHeapFreeRatio used
+// is based on the flags MinMetaspaceFreeRatio and MaxMetaspaceFreeRatio used
 // to resize the Java heap by some GC's.  New flags can be implemented
-// if really needed.  MinHeapFreeRatio is used to calculate how much
+// if really needed.  MinMetaspaceFreeRatio is used to calculate how much
 // free space is desirable in the metaspace capacity to decide how much
 // to increase the HWM.  MaxMetaspaceFreeRatio is used to decide how much
 // free space is desirable in the metaspace capacity before decreasing
@@ -1082,7 +1275,11 @@
 }
 
 bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) {
+
+  size_t committed_capacity_bytes = MetaspaceAux::allocated_capacity_bytes();
   // If the user wants a limit, impose one.
+  size_t max_metaspace_size_bytes = MaxMetaspaceSize;
+  size_t metaspace_size_bytes = MetaspaceSize;
   if (!FLAG_IS_DEFAULT(MaxMetaspaceSize) &&
       MetaspaceAux::reserved_in_bytes() >= MaxMetaspaceSize) {
     return false;
@@ -1094,57 +1291,48 @@
 
   // If this is part of an allocation after a GC, expand
   // unconditionally.
-  if(MetaspaceGC::expand_after_GC()) {
+  if (MetaspaceGC::expand_after_GC()) {
     return true;
   }
 
-  size_t metaspace_size_words = MetaspaceSize / BytesPerWord;
+
 
   // If the capacity is below the minimum capacity, allow the
   // expansion.  Also set the high-water-mark (capacity_until_GC)
   // to that minimum capacity so that a GC will not be induced
   // until that minimum capacity is exceeded.
-  if (vsl->capacity_words_sum() < metaspace_size_words ||
+  if (committed_capacity_bytes < metaspace_size_bytes ||
       capacity_until_GC() == 0) {
-    set_capacity_until_GC(metaspace_size_words);
+    set_capacity_until_GC(metaspace_size_bytes);
     return true;
   } else {
-    if (vsl->capacity_words_sum() < capacity_until_GC()) {
+    if (committed_capacity_bytes < capacity_until_GC()) {
       return true;
     } else {
       if (TraceMetadataChunkAllocation && Verbose) {
         gclog_or_tty->print_cr("  allocation request size " SIZE_FORMAT
                         "  capacity_until_GC " SIZE_FORMAT
-                        "  capacity_words_sum " SIZE_FORMAT
-                        "  used_words_sum " SIZE_FORMAT
-                        "  free chunks " SIZE_FORMAT
-                        "  free chunks count %d",
+                        "  allocated_capacity_bytes " SIZE_FORMAT,
                         word_size,
                         capacity_until_GC(),
-                        vsl->capacity_words_sum(),
-                        vsl->used_words_sum(),
-                        vsl->chunk_manager()->free_chunks_total(),
-                        vsl->chunk_manager()->free_chunks_count());
+                        MetaspaceAux::allocated_capacity_bytes());
       }
       return false;
     }
   }
 }
 
-// Variables are in bytes
+
 
 void MetaspaceGC::compute_new_size() {
   assert(_shrink_factor <= 100, "invalid shrink factor");
   uint current_shrink_factor = _shrink_factor;
   _shrink_factor = 0;
 
-  VirtualSpaceList *vsl = Metaspace::space_list();
-
-  size_t capacity_after_gc = vsl->capacity_bytes_sum();
-  // Check to see if these two can be calculated without walking the CLDG
-  size_t used_after_gc = vsl->used_bytes_sum();
-  size_t capacity_until_GC = vsl->capacity_bytes_sum();
-  size_t free_after_gc = capacity_until_GC - used_after_gc;
+  // Until a faster way of calculating the "used" quantity is implemented,
+  // use "capacity".
+  const size_t used_after_gc = MetaspaceAux::allocated_capacity_bytes();
+  const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC();
 
   const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0;
   const double maximum_used_percentage = 1.0 - minimum_free_percentage;
@@ -1157,45 +1345,34 @@
                                   MetaspaceSize);
 
   if (PrintGCDetails && Verbose) {
-    const double free_percentage = ((double)free_after_gc) / capacity_until_GC;
     gclog_or_tty->print_cr("\nMetaspaceGC::compute_new_size: ");
     gclog_or_tty->print_cr("  "
                   "  minimum_free_percentage: %6.2f"
                   "  maximum_used_percentage: %6.2f",
                   minimum_free_percentage,
                   maximum_used_percentage);
-    double d_free_after_gc = free_after_gc / (double) K;
     gclog_or_tty->print_cr("  "
-                  "   free_after_gc       : %6.1fK"
-                  "   used_after_gc       : %6.1fK"
-                  "   capacity_after_gc   : %6.1fK"
-                  "   metaspace HWM     : %6.1fK",
-                  free_after_gc / (double) K,
-                  used_after_gc / (double) K,
-                  capacity_after_gc / (double) K,
-                  capacity_until_GC / (double) K);
-    gclog_or_tty->print_cr("  "
-                  "   free_percentage: %6.2f",
-                  free_percentage);
+                  "   used_after_gc       : %6.1fKB",
+                  used_after_gc / (double) K);
   }
 
 
+  size_t shrink_bytes = 0;
   if (capacity_until_GC < minimum_desired_capacity) {
     // If we have less capacity below the metaspace HWM, then
     // increment the HWM.
     size_t expand_bytes = minimum_desired_capacity - capacity_until_GC;
     // Don't expand unless it's significant
     if (expand_bytes >= MinMetaspaceExpansion) {
-      size_t expand_words = expand_bytes / BytesPerWord;
-      MetaspaceGC::inc_capacity_until_GC(expand_words);
+      MetaspaceGC::set_capacity_until_GC(capacity_until_GC + expand_bytes);
     }
     if (PrintGCDetails && Verbose) {
-      size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes();
+      size_t new_capacity_until_GC = capacity_until_GC;
       gclog_or_tty->print_cr("    expanding:"
-                    "  minimum_desired_capacity: %6.1fK"
-                    "  expand_words: %6.1fK"
-                    "  MinMetaspaceExpansion: %6.1fK"
-                    "  new metaspace HWM:  %6.1fK",
+                    "  minimum_desired_capacity: %6.1fKB"
+                    "  expand_bytes: %6.1fKB"
+                    "  MinMetaspaceExpansion: %6.1fKB"
+                    "  new metaspace HWM:  %6.1fKB",
                     minimum_desired_capacity / (double) K,
                     expand_bytes / (double) K,
                     MinMetaspaceExpansion / (double) K,
@@ -1205,11 +1382,10 @@
   }
 
   // No expansion, now see if we want to shrink
-  size_t shrink_words = 0;
   // We would never want to shrink more than this
-  size_t max_shrink_words = capacity_until_GC - minimum_desired_capacity;
-  assert(max_shrink_words >= 0, err_msg("max_shrink_words " SIZE_FORMAT,
-    max_shrink_words));
+  size_t max_shrink_bytes = capacity_until_GC - minimum_desired_capacity;
+  assert(max_shrink_bytes >= 0, err_msg("max_shrink_bytes " SIZE_FORMAT,
+    max_shrink_bytes));
 
   // Should shrinking be considered?
   if (MaxMetaspaceFreeRatio < 100) {
@@ -1219,17 +1395,15 @@
     size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));
     maximum_desired_capacity = MAX2(maximum_desired_capacity,
                                     MetaspaceSize);
-    if (PrintGC && Verbose) {
+    if (PrintGCDetails && Verbose) {
       gclog_or_tty->print_cr("  "
                              "  maximum_free_percentage: %6.2f"
                              "  minimum_used_percentage: %6.2f",
                              maximum_free_percentage,
                              minimum_used_percentage);
       gclog_or_tty->print_cr("  "
-                             "  capacity_until_GC: %6.1fK"
-                             "  minimum_desired_capacity: %6.1fK"
-                             "  maximum_desired_capacity: %6.1fK",
-                             capacity_until_GC / (double) K,
+                             "  minimum_desired_capacity: %6.1fKB"
+                             "  maximum_desired_capacity: %6.1fKB",
                              minimum_desired_capacity / (double) K,
                              maximum_desired_capacity / (double) K);
     }
@@ -1239,17 +1413,17 @@
 
     if (capacity_until_GC > maximum_desired_capacity) {
       // Capacity too large, compute shrinking size
-      shrink_words = capacity_until_GC - maximum_desired_capacity;
+      shrink_bytes = capacity_until_GC - maximum_desired_capacity;
       // We don't want shrink all the way back to initSize if people call
       // System.gc(), because some programs do that between "phases" and then
       // we'd just have to grow the heap up again for the next phase.  So we
       // damp the shrinking: 0% on the first call, 10% on the second call, 40%
       // on the third call, and 100% by the fourth call.  But if we recompute
       // size without shrinking, it goes back to 0%.
-      shrink_words = shrink_words / 100 * current_shrink_factor;
-      assert(shrink_words <= max_shrink_words,
+      shrink_bytes = shrink_bytes / 100 * current_shrink_factor;
+      assert(shrink_bytes <= max_shrink_bytes,
         err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT,
-          shrink_words, max_shrink_words));
+          shrink_bytes, max_shrink_bytes));
       if (current_shrink_factor == 0) {
         _shrink_factor = 10;
       } else {
@@ -1263,11 +1437,11 @@
                       MetaspaceSize / (double) K,
                       maximum_desired_capacity / (double) K);
         gclog_or_tty->print_cr("  "
-                      "  shrink_words: %.1fK"
+                      "  shrink_bytes: %.1fK"
                       "  current_shrink_factor: %d"
                       "  new shrink factor: %d"
                       "  MinMetaspaceExpansion: %.1fK",
-                      shrink_words / (double) K,
+                      shrink_bytes / (double) K,
                       current_shrink_factor,
                       _shrink_factor,
                       MinMetaspaceExpansion / (double) K);
@@ -1275,23 +1449,11 @@
     }
   }
 
-
   // Don't shrink unless it's significant
-  if (shrink_words >= MinMetaspaceExpansion) {
-    VirtualSpaceNode* csp = vsl->current_virtual_space();
-    size_t available_to_shrink = csp->capacity_words_in_vs() -
-      csp->used_words_in_vs();
-    shrink_words = MIN2(shrink_words, available_to_shrink);
-    csp->shrink_by(shrink_words);
-    MetaspaceGC::dec_capacity_until_GC(shrink_words);
-    if (PrintGCDetails && Verbose) {
-      size_t new_capacity_until_GC = MetaspaceGC::capacity_until_GC_in_bytes();
-      gclog_or_tty->print_cr("  metaspace HWM: %.1fK", new_capacity_until_GC / (double) K);
-    }
+  if (shrink_bytes >= MinMetaspaceExpansion &&
+      ((capacity_until_GC - shrink_bytes) >= MetaspaceSize)) {
+    MetaspaceGC::set_capacity_until_GC(capacity_until_GC - shrink_bytes);
   }
-  assert(used_after_gc <= vsl->capacity_bytes_sum(),
-         "sanity check");
-
 }
 
 // Metadebug methods
@@ -1567,9 +1729,6 @@
       }
       // Chunk is being removed from the chunks free list.
       dec_free_chunks_total(chunk->capacity_word_size());
-#ifdef ASSERT
-      chunk->set_is_free(false);
-#endif
     } else {
       return NULL;
     }
@@ -1578,6 +1737,11 @@
   // Remove it from the links to this freelist
   chunk->set_next(NULL);
   chunk->set_prev(NULL);
+#ifdef ASSERT
+  // Chunk is no longer on any freelist. Setting to false make container_count_slow()
+  // work.
+  chunk->set_is_free(false);
+#endif
   slow_locked_verify();
   return chunk;
 }
@@ -1692,18 +1856,28 @@
 }
 
 size_t SpaceManager::sum_capacity_in_chunks_in_use() const {
-  MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
-  size_t sum = 0;
-  for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
-    Metachunk* chunk = chunks_in_use(i);
-    while (chunk != NULL) {
-      // Just changed this sum += chunk->capacity_word_size();
-      // sum += chunk->word_size() - Metachunk::overhead();
-      sum += chunk->capacity_word_size();
-      chunk = chunk->next();
+  // For CMS use "allocated_chunks_words()" which does not need the
+  // Metaspace lock.  For the other collectors sum over the
+  // lists.  Use both methods as a check that "allocated_chunks_words()"
+  // is correct.  That is, sum_capacity_in_chunks() is too expensive
+  // to use in the product and allocated_chunks_words() should be used
+  // but allow for  checking that allocated_chunks_words() returns the same
+  // value as sum_capacity_in_chunks_in_use() which is the definitive
+  // answer.
+  if (UseConcMarkSweepGC) {
+    return allocated_chunks_words();
+  } else {
+    MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
+    size_t sum = 0;
+    for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
+      Metachunk* chunk = chunks_in_use(i);
+      while (chunk != NULL) {
+        sum += chunk->capacity_word_size();
+        chunk = chunk->next();
+      }
     }
+  return sum;
   }
-  return sum;
 }
 
 size_t SpaceManager::sum_count_in_chunks_in_use() {
@@ -1861,12 +2035,44 @@
 SpaceManager::SpaceManager(Mutex* lock,
                            VirtualSpaceList* vs_list) :
   _vs_list(vs_list),
-  _allocation_total(0),
+  _allocated_blocks_words(0),
+  _allocated_chunks_words(0),
+  _allocated_chunks_count(0),
   _lock(lock)
 {
   initialize();
 }
 
+void SpaceManager::inc_size_metrics(size_t words) {
+  assert_lock_strong(SpaceManager::expand_lock());
+  // Total of allocated Metachunks and allocated Metachunks count
+  // for each SpaceManager
+  _allocated_chunks_words = _allocated_chunks_words + words;
+  _allocated_chunks_count++;
+  // Global total of capacity in allocated Metachunks
+  MetaspaceAux::inc_capacity(words);
+  // Global total of allocated Metablocks.
+  // used_words_slow() includes the overhead in each
+  // Metachunk so include it in the used when the
+  // Metachunk is first added (so only added once per
+  // Metachunk).
+  MetaspaceAux::inc_used(Metachunk::overhead());
+}
+
+void SpaceManager::inc_used_metrics(size_t words) {
+  // Add to the per SpaceManager total
+  Atomic::add_ptr(words, &_allocated_blocks_words);
+  // Add to the global total
+  MetaspaceAux::inc_used(words);
+}
+
+void SpaceManager::dec_total_from_size_metrics() {
+  MetaspaceAux::dec_capacity(allocated_chunks_words());
+  MetaspaceAux::dec_used(allocated_blocks_words());
+  // Also deduct the overhead per Metachunk
+  MetaspaceAux::dec_used(allocated_chunks_count() * Metachunk::overhead());
+}
+
 void SpaceManager::initialize() {
   Metadebug::init_allocation_fail_alot_count();
   for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
@@ -1887,11 +2093,13 @@
   assert_lock_strong(SpaceManager::expand_lock());
   Metachunk* cur = chunks;
 
-  // This return chunks one at a time.  If a new
+  // This returns chunks one at a time.  If a new
   // class List can be created that is a base class
   // of FreeList then something like FreeList::prepend()
   // can be used in place of this loop
   while (cur != NULL) {
+    assert(cur->container() != NULL, "Container should have been set");
+    cur->container()->dec_container_count();
     // Capture the next link before it is changed
     // by the call to return_chunk_at_head();
     Metachunk* next = cur->next();
@@ -1903,7 +2111,10 @@
 
 SpaceManager::~SpaceManager() {
   // This call this->_lock which can't be done while holding expand_lock()
-  const size_t in_use_before = sum_capacity_in_chunks_in_use();
+  assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(),
+    err_msg("sum_capacity_in_chunks_in_use() " SIZE_FORMAT
+            " allocated_chunks_words() " SIZE_FORMAT,
+            sum_capacity_in_chunks_in_use(), allocated_chunks_words()));
 
   MutexLockerEx fcl(SpaceManager::expand_lock(),
                     Mutex::_no_safepoint_check_flag);
@@ -1912,17 +2123,19 @@
 
   chunk_manager->slow_locked_verify();
 
+  dec_total_from_size_metrics();
+
   if (TraceMetadataChunkAllocation && Verbose) {
     gclog_or_tty->print_cr("~SpaceManager(): " PTR_FORMAT, this);
     locked_print_chunks_in_use_on(gclog_or_tty);
   }
 
-  // Mangle freed memory.
-  NOT_PRODUCT(mangle_freed_chunks();)
+  // Do not mangle freed Metachunks.  The chunk size inside Metachunks
+  // is during the freeing of a VirtualSpaceNodes.
 
   // Have to update before the chunks_in_use lists are emptied
   // below.
-  chunk_manager->inc_free_chunks_total(in_use_before,
+  chunk_manager->inc_free_chunks_total(allocated_chunks_words(),
                                        sum_count_in_chunks_in_use());
 
   // Add all the chunks in use by this space manager
@@ -1978,6 +2191,7 @@
                    " granularity %d",
                    humongous_chunks->word_size(), HumongousChunkGranularity));
     Metachunk* next_humongous_chunks = humongous_chunks->next();
+    humongous_chunks->container()->dec_container_count();
     chunk_manager->humongous_dictionary()->return_chunk(humongous_chunks);
     humongous_chunks = next_humongous_chunks;
   }
@@ -1987,7 +2201,6 @@
                      chunk_manager->humongous_dictionary()->total_count(),
                      chunk_size_name(HumongousIndex));
   }
-  set_chunks_in_use(HumongousIndex, NULL);
   chunk_manager->slow_locked_verify();
 }
 
@@ -2067,12 +2280,17 @@
     assert(new_chunk->word_size() > medium_chunk_size(), "List inconsistency");
   }
 
+  // Add to the running sum of capacity
+  inc_size_metrics(new_chunk->word_size());
+
   assert(new_chunk->is_empty(), "Not ready for reuse");
   if (TraceMetadataChunkAllocation && Verbose) {
     gclog_or_tty->print("SpaceManager::add_chunk: %d) ",
                         sum_count_in_chunks_in_use());
     new_chunk->print_on(gclog_or_tty);
-    vs_list()->chunk_manager()->locked_print_free_chunks(tty);
+    if (vs_list() != NULL) {
+      vs_list()->chunk_manager()->locked_print_free_chunks(tty);
+    }
   }
 }
 
@@ -2143,7 +2361,7 @@
   // of memory if this returns null.
   if (DumpSharedSpaces) {
     assert(current_chunk() != NULL, "should never happen");
-    inc_allocation_total(word_size);
+    inc_used_metrics(word_size);
     return current_chunk()->allocate(word_size); // caller handles null result
   }
   if (current_chunk() != NULL) {
@@ -2154,7 +2372,7 @@
     result = grow_and_allocate(word_size);
   }
   if (result > 0) {
-    inc_allocation_total(word_size);
+    inc_used_metrics(word_size);
     assert(result != (MetaWord*) chunks_in_use(MediumIndex),
            "Head of the list is being allocated");
   }
@@ -2188,20 +2406,14 @@
 }
 
 #ifdef ASSERT
-void SpaceManager::verify_allocation_total() {
+void SpaceManager::verify_allocated_blocks_words() {
   // Verification is only guaranteed at a safepoint.
-  if (SafepointSynchronize::is_at_safepoint()) {
-    gclog_or_tty->print_cr("Chunk " PTR_FORMAT " allocation_total " SIZE_FORMAT
-                           " sum_used_in_chunks_in_use " SIZE_FORMAT,
-                           this,
-                           allocation_total(),
-                           sum_used_in_chunks_in_use());
-  }
-  MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag);
-  assert(allocation_total() == sum_used_in_chunks_in_use(),
+  assert(SafepointSynchronize::is_at_safepoint() || !Universe::is_fully_initialized(),
+    "Verification can fail if the applications is running");
+  assert(allocated_blocks_words() == sum_used_in_chunks_in_use(),
     err_msg("allocation total is not consistent " SIZE_FORMAT
             " vs " SIZE_FORMAT,
-            allocation_total(), sum_used_in_chunks_in_use()));
+            allocated_blocks_words(), sum_used_in_chunks_in_use()));
 }
 
 #endif
@@ -2257,14 +2469,65 @@
 
 // MetaspaceAux
 
-size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) {
+
+size_t MetaspaceAux::_allocated_capacity_words = 0;
+size_t MetaspaceAux::_allocated_used_words = 0;
+
+size_t MetaspaceAux::free_bytes() {
+  size_t result = 0;
+  if (Metaspace::class_space_list() != NULL) {
+    result = result + Metaspace::class_space_list()->free_bytes();
+  }
+  if (Metaspace::space_list() != NULL) {
+    result = result + Metaspace::space_list()->free_bytes();
+  }
+  return result;
+}
+
+void MetaspaceAux::dec_capacity(size_t words) {
+  assert_lock_strong(SpaceManager::expand_lock());
+  assert(words <= _allocated_capacity_words,
+    err_msg("About to decrement below 0: words " SIZE_FORMAT
+            " is greater than _allocated_capacity_words " SIZE_FORMAT,
+            words, _allocated_capacity_words));
+  _allocated_capacity_words = _allocated_capacity_words - words;
+}
+
+void MetaspaceAux::inc_capacity(size_t words) {
+  assert_lock_strong(SpaceManager::expand_lock());
+  // Needs to be atomic
+  _allocated_capacity_words = _allocated_capacity_words + words;
+}
+
+void MetaspaceAux::dec_used(size_t words) {
+  assert(words <= _allocated_used_words,
+    err_msg("About to decrement below 0: words " SIZE_FORMAT
+            " is greater than _allocated_used_words " SIZE_FORMAT,
+            words, _allocated_used_words));
+  // For CMS deallocation of the Metaspaces occurs during the
+  // sweep which is a concurrent phase.  Protection by the expand_lock()
+  // is not enough since allocation is on a per Metaspace basis
+  // and protected by the Metaspace lock.
+  jlong minus_words = (jlong) - (jlong) words;
+  Atomic::add_ptr(minus_words, &_allocated_used_words);
+}
+
+void MetaspaceAux::inc_used(size_t words) {
+  // _allocated_used_words tracks allocations for
+  // each piece of metadata.  Those allocations are
+  // generally done concurrently by different application
+  // threads so must be done atomically.
+  Atomic::add_ptr(words, &_allocated_used_words);
+}
+
+size_t MetaspaceAux::used_bytes_slow(Metaspace::MetadataType mdtype) {
   size_t used = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
     Metaspace* msp = iter.get_next();
-    // Sum allocation_total for each metaspace
+    // Sum allocated_blocks_words for each metaspace
     if (msp != NULL) {
-      used += msp->used_words(mdtype);
+      used += msp->used_words_slow(mdtype);
     }
   }
   return used * BytesPerWord;
@@ -2282,13 +2545,15 @@
   return free * BytesPerWord;
 }
 
-size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
-  size_t capacity = free_chunks_total(mdtype);
+size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) {
+  // Don't count the space in the freelists.  That space will be
+  // added to the capacity calculation as needed.
+  size_t capacity = 0;
   ClassLoaderDataGraphMetaspaceIterator iter;
   while (iter.repeat()) {
     Metaspace* msp = iter.get_next();
     if (msp != NULL) {
-      capacity += msp->capacity_words(mdtype);
+      capacity += msp->capacity_words_slow(mdtype);
     }
   }
   return capacity * BytesPerWord;
@@ -2315,23 +2580,30 @@
   return free_chunks_total(mdtype) * BytesPerWord;
 }
 
+size_t MetaspaceAux::free_chunks_total() {
+  return free_chunks_total(Metaspace::ClassType) +
+         free_chunks_total(Metaspace::NonClassType);
+}
+
+size_t MetaspaceAux::free_chunks_total_in_bytes() {
+  return free_chunks_total() * BytesPerWord;
+}
+
 void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) {
   gclog_or_tty->print(", [Metaspace:");
   if (PrintGCDetails && Verbose) {
     gclog_or_tty->print(" "  SIZE_FORMAT
                         "->" SIZE_FORMAT
-                        "("  SIZE_FORMAT "/" SIZE_FORMAT ")",
+                        "("  SIZE_FORMAT ")",
                         prev_metadata_used,
-                        used_in_bytes(),
-                        capacity_in_bytes(),
+                        allocated_capacity_bytes(),
                         reserved_in_bytes());
   } else {
     gclog_or_tty->print(" "  SIZE_FORMAT "K"
                         "->" SIZE_FORMAT "K"
-                        "("  SIZE_FORMAT "K/" SIZE_FORMAT "K)",
+                        "("  SIZE_FORMAT "K)",
                         prev_metadata_used / K,
-                        used_in_bytes()/ K,
-                        capacity_in_bytes()/K,
+                        allocated_capacity_bytes() / K,
                         reserved_in_bytes()/ K);
   }
 
@@ -2346,23 +2618,30 @@
   out->print_cr(" Metaspace total "
                 SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
                 " reserved " SIZE_FORMAT "K",
-                capacity_in_bytes()/K, used_in_bytes()/K, reserved_in_bytes()/K);
-  out->print_cr("  data space     "
-                SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
-                " reserved " SIZE_FORMAT "K",
-                capacity_in_bytes(nct)/K, used_in_bytes(nct)/K, reserved_in_bytes(nct)/K);
-  out->print_cr("  class space    "
-                SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
-                " reserved " SIZE_FORMAT "K",
-                capacity_in_bytes(ct)/K, used_in_bytes(ct)/K, reserved_in_bytes(ct)/K);
+                allocated_capacity_bytes()/K, allocated_used_bytes()/K, reserved_in_bytes()/K);
+#if 0
+// The calls to capacity_bytes_slow() and used_bytes_slow() cause
+// lock ordering assertion failures with some collectors.  Do
+// not include this code until the lock ordering is fixed.
+  if (PrintGCDetails && Verbose) {
+    out->print_cr("  data space     "
+                  SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
+                  " reserved " SIZE_FORMAT "K",
+                  capacity_bytes_slow(nct)/K, used_bytes_slow(nct)/K, reserved_in_bytes(nct)/K);
+    out->print_cr("  class space    "
+                  SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
+                  " reserved " SIZE_FORMAT "K",
+                  capacity_bytes_slow(ct)/K, used_bytes_slow(ct)/K, reserved_in_bytes(ct)/K);
+  }
+#endif
 }
 
 // Print information for class space and data space separately.
 // This is almost the same as above.
 void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) {
   size_t free_chunks_capacity_bytes = free_chunks_total_in_bytes(mdtype);
-  size_t capacity_bytes = capacity_in_bytes(mdtype);
-  size_t used_bytes = used_in_bytes(mdtype);
+  size_t capacity_bytes = capacity_bytes_slow(mdtype);
+  size_t used_bytes = used_bytes_slow(mdtype);
   size_t free_bytes = free_in_bytes(mdtype);
   size_t used_and_free = used_bytes + free_bytes +
                            free_chunks_capacity_bytes;
@@ -2435,6 +2714,36 @@
   Metaspace::class_space_list()->chunk_manager()->verify();
 }
 
+void MetaspaceAux::verify_capacity() {
+#ifdef ASSERT
+  size_t running_sum_capacity_bytes = allocated_capacity_bytes();
+  // For purposes of the running sum of used, verify against capacity
+  size_t capacity_in_use_bytes = capacity_bytes_slow();
+  assert(running_sum_capacity_bytes == capacity_in_use_bytes,
+    err_msg("allocated_capacity_words() * BytesPerWord " SIZE_FORMAT
+            " capacity_bytes_slow()" SIZE_FORMAT,
+            running_sum_capacity_bytes, capacity_in_use_bytes));
+#endif
+}
+
+void MetaspaceAux::verify_used() {
+#ifdef ASSERT
+  size_t running_sum_used_bytes = allocated_used_bytes();
+  // For purposes of the running sum of used, verify against capacity
+  size_t used_in_use_bytes = used_bytes_slow();
+  assert(allocated_used_bytes() == used_in_use_bytes,
+    err_msg("allocated_used_bytes() " SIZE_FORMAT
+            " used_bytes_slow()()" SIZE_FORMAT,
+            allocated_used_bytes(), used_in_use_bytes));
+#endif
+}
+
+void MetaspaceAux::verify_metrics() {
+  verify_capacity();
+  verify_used();
+}
+
+
 // Metaspace methods
 
 size_t Metaspace::_first_chunk_word_size = 0;
@@ -2584,8 +2893,8 @@
   MetaWord* result;
   MetaspaceGC::set_expand_after_GC(true);
   size_t before_inc = MetaspaceGC::capacity_until_GC();
-  size_t delta_words = MetaspaceGC::delta_capacity_until_GC(word_size);
-  MetaspaceGC::inc_capacity_until_GC(delta_words);
+  size_t delta_bytes = MetaspaceGC::delta_capacity_until_GC(word_size) * BytesPerWord;
+  MetaspaceGC::inc_capacity_until_GC(delta_bytes);
   if (PrintGCDetails && Verbose) {
     gclog_or_tty->print_cr("Increase capacity to GC from " SIZE_FORMAT
       " to " SIZE_FORMAT, before_inc, MetaspaceGC::capacity_until_GC());
@@ -2603,8 +2912,8 @@
   return (char*)vsm()->current_chunk()->bottom();
 }
 
-size_t Metaspace::used_words(MetadataType mdtype) const {
-  // return vsm()->allocation_total();
+size_t Metaspace::used_words_slow(MetadataType mdtype) const {
+  // return vsm()->allocated_used_words();
   return mdtype == ClassType ? class_vsm()->sum_used_in_chunks_in_use() :
                                vsm()->sum_used_in_chunks_in_use();  // includes overhead!
 }
@@ -2619,16 +2928,24 @@
 // have been made. Don't include space in the global freelist and
 // in the space available in the dictionary which
 // is already counted in some chunk.
-size_t Metaspace::capacity_words(MetadataType mdtype) const {
+size_t Metaspace::capacity_words_slow(MetadataType mdtype) const {
   return mdtype == ClassType ? class_vsm()->sum_capacity_in_chunks_in_use() :
                                vsm()->sum_capacity_in_chunks_in_use();
 }
 
+size_t Metaspace::used_bytes_slow(MetadataType mdtype) const {
+  return used_words_slow(mdtype) * BytesPerWord;
+}
+
+size_t Metaspace::capacity_bytes_slow(MetadataType mdtype) const {
+  return capacity_words_slow(mdtype) * BytesPerWord;
+}
+
 void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
   if (SafepointSynchronize::is_at_safepoint()) {
     assert(Thread::current()->is_VM_thread(), "should be the VM thread");
     // Don't take Heap_lock
-    MutexLocker ml(vsm()->lock());
+    MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
     if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
       // Dark matter.  Too small for dictionary.
 #ifdef ASSERT
@@ -2642,7 +2959,7 @@
       vsm()->deallocate(ptr, word_size);
     }
   } else {
-    MutexLocker ml(vsm()->lock());
+    MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
 
     if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
       // Dark matter.  Too small for dictionary.
@@ -2716,6 +3033,13 @@
   return Metablock::initialize(result, word_size);
 }
 
+void Metaspace::purge() {
+  MutexLockerEx cl(SpaceManager::expand_lock(),
+                   Mutex::_no_safepoint_check_flag);
+  space_list()->purge();
+  class_space_list()->purge();
+}
+
 void Metaspace::print_on(outputStream* out) const {
   // Print both class virtual space counts and metaspace.
   if (Verbose) {
@@ -2733,7 +3057,8 @@
   // aren't deleted presently.  When they are, some sort of locking might
   // be needed.  Note, locking this can cause inversion problems with the
   // caller in MetaspaceObj::is_metadata() function.
-  return space_list()->contains(ptr) || class_space_list()->contains(ptr);
+  return space_list()->contains(ptr) ||
+         class_space_list()->contains(ptr);
 }
 
 void Metaspace::verify() {
@@ -2742,10 +3067,6 @@
 }
 
 void Metaspace::dump(outputStream* const out) const {
-  if (UseMallocOnly) {
-    // Just print usage for now
-    out->print_cr("usage %d", used_words(Metaspace::NonClassType));
-  }
   out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, vsm());
   vsm()->dump(out);
   out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm());
--- a/hotspot/src/share/vm/memory/metaspace.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspace.hpp	Thu May 16 11:47:51 2013 +0100
@@ -111,6 +111,10 @@
   SpaceManager* _class_vsm;
   SpaceManager* class_vsm() const { return _class_vsm; }
 
+  // Allocate space for metadata of type mdtype. This is space
+  // within a Metachunk and is used by
+  //   allocate(ClassLoaderData*, size_t, bool, MetadataType, TRAPS)
+  // which returns a Metablock.
   MetaWord* allocate(size_t word_size, MetadataType mdtype);
 
   // Virtual Space lists for both classes and other metadata
@@ -133,11 +137,14 @@
   static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; }
 
   char*  bottom() const;
-  size_t used_words(MetadataType mdtype) const;
+  size_t used_words_slow(MetadataType mdtype) const;
   size_t free_words(MetadataType mdtype) const;
-  size_t capacity_words(MetadataType mdtype) const;
+  size_t capacity_words_slow(MetadataType mdtype) const;
   size_t waste_words(MetadataType mdtype) const;
 
+  size_t used_bytes_slow(MetadataType mdtype) const;
+  size_t capacity_bytes_slow(MetadataType mdtype) const;
+
   static Metablock* allocate(ClassLoaderData* loader_data, size_t size,
                             bool read_only, MetadataType mdtype, TRAPS);
   void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
@@ -150,6 +157,9 @@
   static bool contains(const void *ptr);
   void dump(outputStream* const out) const;
 
+  // Free empty virtualspaces
+  static void purge();
+
   void print_on(outputStream* st) const;
   // Debugging support
   void verify();
@@ -158,28 +168,81 @@
 class MetaspaceAux : AllStatic {
 
   // Statistics for class space and data space in metaspace.
-  static size_t used_in_bytes(Metaspace::MetadataType mdtype);
+
+  // These methods iterate over the classloader data graph
+  // for the given Metaspace type.  These are slow.
+  static size_t used_bytes_slow(Metaspace::MetadataType mdtype);
   static size_t free_in_bytes(Metaspace::MetadataType mdtype);
-  static size_t capacity_in_bytes(Metaspace::MetadataType mdtype);
+  static size_t capacity_bytes_slow(Metaspace::MetadataType mdtype);
+
+  // Iterates over the virtual space list.
   static size_t reserved_in_bytes(Metaspace::MetadataType mdtype);
 
   static size_t free_chunks_total(Metaspace::MetadataType mdtype);
   static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
 
  public:
-  // Total of space allocated to metadata in all Metaspaces
-  static size_t used_in_bytes() {
-    return used_in_bytes(Metaspace::ClassType) +
-           used_in_bytes(Metaspace::NonClassType);
+  // Running sum of space in all Metachunks that has been
+  // allocated to a Metaspace.  This is used instead of
+  // iterating over all the classloaders
+  static size_t _allocated_capacity_words;
+  // Running sum of space in all Metachunks that have
+  // are being used for metadata.
+  static size_t _allocated_used_words;
+
+ public:
+  // Decrement and increment _allocated_capacity_words
+  static void dec_capacity(size_t words);
+  static void inc_capacity(size_t words);
+
+  // Decrement and increment _allocated_used_words
+  static void dec_used(size_t words);
+  static void inc_used(size_t words);
+
+  // Total of space allocated to metadata in all Metaspaces.
+  // This sums the space used in each Metachunk by
+  // iterating over the classloader data graph
+  static size_t used_bytes_slow() {
+    return used_bytes_slow(Metaspace::ClassType) +
+           used_bytes_slow(Metaspace::NonClassType);
   }
 
-  // Total of available space in all Metaspaces
-  // Total of capacity allocated to all Metaspaces.  This includes
-  // space in Metachunks not yet allocated and in the Metachunk
-  // freelist.
-  static size_t capacity_in_bytes() {
-    return capacity_in_bytes(Metaspace::ClassType) +
-           capacity_in_bytes(Metaspace::NonClassType);
+  // Used by MetaspaceCounters
+  static size_t free_chunks_total();
+  static size_t free_chunks_total_in_bytes();
+
+  static size_t allocated_capacity_words() {
+    return _allocated_capacity_words;
+  }
+  static size_t allocated_capacity_bytes() {
+    return _allocated_capacity_words * BytesPerWord;
+  }
+
+  static size_t allocated_used_words() {
+    return _allocated_used_words;
+  }
+  static size_t allocated_used_bytes() {
+    return _allocated_used_words * BytesPerWord;
+  }
+
+  static size_t free_bytes();
+
+  // Total capacity in all Metaspaces
+  static size_t capacity_bytes_slow() {
+#ifdef PRODUCT
+    // Use allocated_capacity_bytes() in PRODUCT instead of this function.
+    guarantee(false, "Should not call capacity_bytes_slow() in the PRODUCT");
+#endif
+    size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType);
+    size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType);
+    assert(allocated_capacity_bytes() == class_capacity + non_class_capacity,
+           err_msg("bad accounting: allocated_capacity_bytes() " SIZE_FORMAT
+             " class_capacity + non_class_capacity " SIZE_FORMAT
+             " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT,
+             allocated_capacity_bytes(), class_capacity + non_class_capacity,
+             class_capacity, non_class_capacity));
+
+    return class_capacity + non_class_capacity;
   }
 
   // Total space reserved in all Metaspaces
@@ -198,6 +261,11 @@
   static void print_waste(outputStream* out);
   static void dump(outputStream* out);
   static void verify_free_chunks();
+  // Checks that the values returned by allocated_capacity_bytes() and
+  // capacity_bytes_slow() are the same.
+  static void verify_capacity();
+  static void verify_used();
+  static void verify_metrics();
 };
 
 // Metaspace are deallocated when their class loader are GC'ed.
@@ -232,7 +300,6 @@
  public:
 
   static size_t capacity_until_GC() { return _capacity_until_GC; }
-  static size_t capacity_until_GC_in_bytes() { return _capacity_until_GC * BytesPerWord; }
   static void inc_capacity_until_GC(size_t v) { _capacity_until_GC += v; }
   static void dec_capacity_until_GC(size_t v) {
     _capacity_until_GC = _capacity_until_GC > v ? _capacity_until_GC - v : 0;
--- a/hotspot/src/share/vm/memory/metaspaceCounters.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.cpp	Thu May 16 11:47:51 2013 +0100
@@ -29,6 +29,16 @@
 
 MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL;
 
+size_t MetaspaceCounters::calc_total_capacity() {
+  // The total capacity is the sum of
+  //   1) capacity of Metachunks in use by all Metaspaces
+  //   2) unused space at the end of each Metachunk
+  //   3) space in the freelist
+  size_t total_capacity = MetaspaceAux::allocated_capacity_bytes()
+    + MetaspaceAux::free_bytes() + MetaspaceAux::free_chunks_total_in_bytes();
+  return total_capacity;
+}
+
 MetaspaceCounters::MetaspaceCounters() :
     _capacity(NULL),
     _used(NULL),
@@ -36,8 +46,8 @@
   if (UsePerfData) {
     size_t min_capacity = MetaspaceAux::min_chunk_size();
     size_t max_capacity = MetaspaceAux::reserved_in_bytes();
-    size_t curr_capacity = MetaspaceAux::capacity_in_bytes();
-    size_t used = MetaspaceAux::used_in_bytes();
+    size_t curr_capacity = calc_total_capacity();
+    size_t used = MetaspaceAux::allocated_used_bytes();
 
     initialize(min_capacity, max_capacity, curr_capacity, used);
   }
@@ -82,15 +92,13 @@
 
 void MetaspaceCounters::update_capacity() {
   assert(UsePerfData, "Should not be called unless being used");
-  assert(_capacity != NULL, "Should be initialized");
-  size_t capacity_in_bytes = MetaspaceAux::capacity_in_bytes();
-  _capacity->set_value(capacity_in_bytes);
+  size_t total_capacity = calc_total_capacity();
+  _capacity->set_value(total_capacity);
 }
 
 void MetaspaceCounters::update_used() {
   assert(UsePerfData, "Should not be called unless being used");
-  assert(_used != NULL, "Should be initialized");
-  size_t used_in_bytes = MetaspaceAux::used_in_bytes();
+  size_t used_in_bytes = MetaspaceAux::allocated_used_bytes();
   _used->set_value(used_in_bytes);
 }
 
--- a/hotspot/src/share/vm/memory/metaspaceCounters.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspaceCounters.hpp	Thu May 16 11:47:51 2013 +0100
@@ -37,6 +37,7 @@
                   size_t max_capacity,
                   size_t curr_capacity,
                   size_t used);
+  size_t calc_total_capacity();
  public:
   MetaspaceCounters();
   ~MetaspaceCounters();
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Thu May 16 11:47:51 2013 +0100
@@ -376,18 +376,17 @@
   const char* fmt = "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " PTR_FORMAT;
   Metaspace* ro_space = _loader_data->ro_metaspace();
   Metaspace* rw_space = _loader_data->rw_metaspace();
-  const size_t BPW = BytesPerWord;
 
   // Allocated size of each space (may not be all occupied)
-  const size_t ro_alloced = ro_space->capacity_words(Metaspace::NonClassType) * BPW;
-  const size_t rw_alloced = rw_space->capacity_words(Metaspace::NonClassType) * BPW;
+  const size_t ro_alloced = ro_space->capacity_bytes_slow(Metaspace::NonClassType);
+  const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType);
   const size_t md_alloced = md_end-md_low;
   const size_t mc_alloced = mc_end-mc_low;
   const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced;
 
   // Occupied size of each space.
-  const size_t ro_bytes = ro_space->used_words(Metaspace::NonClassType) * BPW;
-  const size_t rw_bytes = rw_space->used_words(Metaspace::NonClassType) * BPW;
+  const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType);
+  const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType);
   const size_t md_bytes = size_t(md_top - md_low);
   const size_t mc_bytes = size_t(mc_top - mc_low);
 
--- a/hotspot/src/share/vm/memory/sharedHeap.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/sharedHeap.cpp	Thu May 16 11:47:51 2013 +0100
@@ -218,14 +218,13 @@
 static AlwaysTrueClosure always_true;
 
 void SharedHeap::process_weak_roots(OopClosure* root_closure,
-                                    CodeBlobClosure* code_roots,
-                                    OopClosure* non_root_closure) {
+                                    CodeBlobClosure* code_roots) {
   // Global (weak) JNI handles
   JNIHandles::weak_oops_do(&always_true, root_closure);
 
   CodeCache::blobs_do(code_roots);
-    StringTable::oops_do(root_closure);
-  }
+  StringTable::oops_do(root_closure);
+}
 
 void SharedHeap::set_barrier_set(BarrierSet* bs) {
   _barrier_set = bs;
--- a/hotspot/src/share/vm/memory/sharedHeap.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/sharedHeap.hpp	Thu May 16 11:47:51 2013 +0100
@@ -249,8 +249,7 @@
   // JNI weak roots, the code cache, system dictionary, symbol table,
   // string table.
   void process_weak_roots(OopClosure* root_closure,
-                          CodeBlobClosure* code_roots,
-                          OopClosure* non_root_closure);
+                          CodeBlobClosure* code_roots);
 
   // The functions below are helper functions that a subclass of
   // "SharedHeap" can use in the implementation of its virtual
--- a/hotspot/src/share/vm/memory/universe.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/universe.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1270,7 +1270,7 @@
   st->print_cr("}");
 }
 
-void Universe::verify(bool silent, VerifyOption option) {
+void Universe::verify(VerifyOption option, const char* prefix, bool silent) {
   // The use of _verify_in_progress is a temporary work around for
   // 6320749.  Don't bother with a creating a class to set and clear
   // it since it is only used in this method and the control flow is
@@ -1287,11 +1287,12 @@
   HandleMark hm;  // Handles created during verification can be zapped
   _verify_count++;
 
+  if (!silent) gclog_or_tty->print(prefix);
   if (!silent) gclog_or_tty->print("[Verifying ");
   if (!silent) gclog_or_tty->print("threads ");
   Threads::verify();
+  if (!silent) gclog_or_tty->print("heap ");
   heap()->verify(silent, option);
-
   if (!silent) gclog_or_tty->print("syms ");
   SymbolTable::verify();
   if (!silent) gclog_or_tty->print("strs ");
--- a/hotspot/src/share/vm/memory/universe.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/memory/universe.hpp	Thu May 16 11:47:51 2013 +0100
@@ -445,12 +445,12 @@
 
   // Debugging
   static bool verify_in_progress() { return _verify_in_progress; }
-  static void verify(bool silent, VerifyOption option);
-  static void verify(bool silent) {
-    verify(silent, VerifyOption_Default /* option */);
+  static void verify(VerifyOption option, const char* prefix, bool silent = VerifySilently);
+  static void verify(const char* prefix, bool silent = VerifySilently) {
+    verify(VerifyOption_Default, prefix, silent);
   }
-  static void verify() {
-    verify(false /* silent */);
+  static void verify(bool silent = VerifySilently) {
+    verify("", silent);
   }
 
   static int  verify_count()       { return _verify_count; }
--- a/hotspot/src/share/vm/oops/constantPool.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.cpp	Thu May 16 11:47:51 2013 +0100
@@ -40,6 +40,7 @@
 #include "runtime/init.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/signature.hpp"
+#include "runtime/synchronizer.hpp"
 #include "runtime/vframe.hpp"
 
 ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
@@ -69,7 +70,6 @@
 
   // only set to non-zero if constant pool is merged by RedefineClasses
   set_version(0);
-  set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
 
   // initialize tag array
   int length = tags->length();
@@ -95,9 +95,6 @@
 void ConstantPool::release_C_heap_structures() {
   // walk constant pool and decrement symbol reference counts
   unreference_symbols();
-
-  delete _lock;
-  set_lock(NULL);
 }
 
 objArrayOop ConstantPool::resolved_references() const {
@@ -154,9 +151,6 @@
       ClassLoaderData* loader_data = pool_holder()->class_loader_data();
       set_resolved_references(loader_data->add_handle(refs_handle));
     }
-
-    // Also need to recreate the mutex.  Make sure this matches the constructor
-    set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
   }
 }
 
@@ -167,7 +161,23 @@
   set_resolved_reference_length(
     resolved_references() != NULL ? resolved_references()->length() : 0);
   set_resolved_references(NULL);
-  set_lock(NULL);
+}
+
+oop ConstantPool::lock() {
+  if (_pool_holder) {
+    // We re-use the _pool_holder's init_lock to reduce footprint.
+    // Notes on deadlocks:
+    // [1] This lock is a Java oop, so it can be recursively locked by
+    //     the same thread without self-deadlocks.
+    // [2] Deadlock will happen if there is circular dependency between
+    //     the <clinit> of two Java classes. However, in this case,
+    //     the deadlock would have happened long before we reach
+    //     ConstantPool::lock(), so reusing init_lock does not
+    //     increase the possibility of deadlock.
+    return _pool_holder->init_lock();
+  } else {
+    return NULL;
+  }
 }
 
 int ConstantPool::cp_to_object_index(int cp_index) {
@@ -208,7 +218,9 @@
 
   Symbol* name = NULL;
   Handle       loader;
-  {  MonitorLockerEx ml(this_oop->lock());
+  {
+    oop cplock = this_oop->lock();
+    ObjectLocker ol(cplock , THREAD, cplock != NULL);
 
     if (this_oop->tag_at(which).is_unresolved_klass()) {
       if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
@@ -255,7 +267,8 @@
 
       bool throw_orig_error = false;
       {
-        MonitorLockerEx ml(this_oop->lock());
+        oop cplock = this_oop->lock();
+        ObjectLocker ol(cplock, THREAD, cplock != NULL);
 
         // some other thread has beaten us and has resolved the class.
         if (this_oop->tag_at(which).is_klass()) {
@@ -323,7 +336,8 @@
       }
       return k();
     } else {
-      MonitorLockerEx ml(this_oop->lock());
+      oop cplock = this_oop->lock();
+      ObjectLocker ol(cplock, THREAD, cplock != NULL);
       // Only updated constant pool - if it is resolved.
       do_resolve = this_oop->tag_at(which).is_unresolved_klass();
       if (do_resolve) {
@@ -619,7 +633,8 @@
                                      int tag, TRAPS) {
   ResourceMark rm;
   Symbol* error = PENDING_EXCEPTION->klass()->name();
-  MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
+  oop cplock = this_oop->lock();
+  ObjectLocker ol(cplock, THREAD, cplock != NULL);  // lock cpool to change tag.
 
   int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
            JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
@@ -780,7 +795,8 @@
   if (cache_index >= 0) {
     // Cache the oop here also.
     Handle result_handle(THREAD, result_oop);
-    MonitorLockerEx ml(this_oop->lock());  // don't know if we really need this
+    oop cplock = this_oop->lock();
+    ObjectLocker ol(cplock, THREAD, cplock != NULL);  // don't know if we really need this
     oop result = this_oop->resolved_references()->obj_at(cache_index);
     // Benign race condition:  resolved_references may already be filled in while we were trying to lock.
     // The important thing here is that all threads pick up the same result.
@@ -1043,24 +1059,13 @@
 
   case JVM_CONSTANT_InvokeDynamic:
   {
-    int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
-    int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
-    bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
-    if (!match)  return false;
-    k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
-    k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
-    match = compare_entry_to(k1, cp2, k2, CHECK_false);
-    if (!match)  return false;
-    int argc = invoke_dynamic_argument_count_at(index1);
-    if (argc == cp2->invoke_dynamic_argument_count_at(index2)) {
-      for (int j = 0; j < argc; j++) {
-        k1 = invoke_dynamic_argument_index_at(index1, j);
-        k2 = cp2->invoke_dynamic_argument_index_at(index2, j);
-        match = compare_entry_to(k1, cp2, k2, CHECK_false);
-        if (!match)  return false;
-      }
-      return true;           // got through loop; all elements equal
-    }
+    int k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
+    int k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
+    int i1 = invoke_dynamic_bootstrap_specifier_index(index1);
+    int i2 = cp2->invoke_dynamic_bootstrap_specifier_index(index2);
+    bool match = compare_entry_to(k1, cp2, k2, CHECK_false) &&
+                 compare_operand_to(i1, cp2, i2, CHECK_false);
+    return match;
   } break;
 
   case JVM_CONSTANT_String:
@@ -1095,6 +1100,80 @@
 } // end compare_entry_to()
 
 
+// Resize the operands array with delta_len and delta_size.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::resize_operands(int delta_len, int delta_size, TRAPS) {
+  int old_len  = operand_array_length(operands());
+  int new_len  = old_len + delta_len;
+  int min_len  = (delta_len > 0) ? old_len : new_len;
+
+  int old_size = operands()->length();
+  int new_size = old_size + delta_size;
+  int min_size = (delta_size > 0) ? old_size : new_size;
+
+  ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+  Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, new_size, CHECK);
+
+  // Set index in the resized array for existing elements only
+  for (int idx = 0; idx < min_len; idx++) {
+    int offset = operand_offset_at(idx);                       // offset in original array
+    operand_offset_at_put(new_ops, idx, offset + 2*delta_len); // offset in resized array
+  }
+  // Copy the bootstrap specifiers only
+  Copy::conjoint_memory_atomic(operands()->adr_at(2*old_len),
+                               new_ops->adr_at(2*new_len),
+                               (min_size - 2*min_len) * sizeof(u2));
+  // Explicitly deallocate old operands array.
+  // Note, it is not needed for 7u backport.
+  if ( operands() != NULL) { // the safety check
+    MetadataFactory::free_array<u2>(loader_data, operands());
+  }
+  set_operands(new_ops);
+} // end resize_operands()
+
+
+// Extend the operands array with the length and size of the ext_cp operands.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::extend_operands(constantPoolHandle ext_cp, TRAPS) {
+  int delta_len = operand_array_length(ext_cp->operands());
+  if (delta_len == 0) {
+    return; // nothing to do
+  }
+  int delta_size = ext_cp->operands()->length();
+
+  assert(delta_len  > 0 && delta_size > 0, "extended operands array must be bigger");
+
+  if (operand_array_length(operands()) == 0) {
+    ClassLoaderData* loader_data = pool_holder()->class_loader_data();
+    Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, delta_size, CHECK);
+    // The first element index defines the offset of second part
+    operand_offset_at_put(new_ops, 0, 2*delta_len); // offset in new array
+    set_operands(new_ops);
+  } else {
+    resize_operands(delta_len, delta_size, CHECK);
+  }
+
+} // end extend_operands()
+
+
+// Shrink the operands array to a smaller array with new_len length.
+// Used in RedefineClasses for CP merge.
+void ConstantPool::shrink_operands(int new_len, TRAPS) {
+  int old_len = operand_array_length(operands());
+  if (new_len == old_len) {
+    return; // nothing to do
+  }
+  assert(new_len < old_len, "shrunken operands array must be smaller");
+
+  int free_base  = operand_next_offset_at(new_len - 1);
+  int delta_len  = new_len - old_len;
+  int delta_size = 2*delta_len + free_base - operands()->length();
+
+  resize_operands(delta_len, delta_size, CHECK);
+
+} // end shrink_operands()
+
+
 void ConstantPool::copy_operands(constantPoolHandle from_cp,
                                  constantPoolHandle to_cp,
                                  TRAPS) {
@@ -1357,6 +1436,46 @@
 } // end find_matching_entry()
 
 
+// Compare this constant pool's bootstrap specifier at idx1 to the constant pool
+// cp2's bootstrap specifier at idx2.
+bool ConstantPool::compare_operand_to(int idx1, constantPoolHandle cp2, int idx2, TRAPS) {
+  int k1 = operand_bootstrap_method_ref_index_at(idx1);
+  int k2 = cp2->operand_bootstrap_method_ref_index_at(idx2);
+  bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
+
+  if (!match) {
+    return false;
+  }
+  int argc = operand_argument_count_at(idx1);
+  if (argc == cp2->operand_argument_count_at(idx2)) {
+    for (int j = 0; j < argc; j++) {
+      k1 = operand_argument_index_at(idx1, j);
+      k2 = cp2->operand_argument_index_at(idx2, j);
+      match = compare_entry_to(k1, cp2, k2, CHECK_false);
+      if (!match) {
+        return false;
+      }
+    }
+    return true;           // got through loop; all elements equal
+  }
+  return false;
+} // end compare_operand_to()
+
+// Search constant pool search_cp for a bootstrap specifier that matches
+// this constant pool's bootstrap specifier at pattern_i index.
+// Return the index of a matching bootstrap specifier or (-1) if there is no match.
+int ConstantPool::find_matching_operand(int pattern_i,
+                    constantPoolHandle search_cp, int search_len, TRAPS) {
+  for (int i = 0; i < search_len; i++) {
+    bool found = compare_operand_to(pattern_i, search_cp, i, CHECK_(-1));
+    if (found) {
+      return i;
+    }
+  }
+  return -1;  // bootstrap specifier not found; return unused index (-1)
+} // end find_matching_operand()
+
+
 #ifndef PRODUCT
 
 const char* ConstantPool::printable_name_at(int which) {
--- a/hotspot/src/share/vm/oops/constantPool.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.hpp	Thu May 16 11:47:51 2013 +0100
@@ -111,7 +111,6 @@
     int                _version;
   } _saved;
 
-  Monitor*             _lock;
 
   void set_tags(Array<u1>* tags)               { _tags = tags; }
   void tag_at_put(int which, jbyte t)          { tags()->at_put(which, t); }
@@ -567,6 +566,47 @@
          _indy_argc_offset = 1,  // u2 argc
          _indy_argv_offset = 2   // u2 argv[argc]
   };
+
+  // These functions are used in RedefineClasses for CP merge
+
+  int operand_offset_at(int bootstrap_specifier_index) {
+    assert(0 <= bootstrap_specifier_index &&
+           bootstrap_specifier_index < operand_array_length(operands()),
+           "Corrupted CP operands");
+    return operand_offset_at(operands(), bootstrap_specifier_index);
+  }
+  int operand_bootstrap_method_ref_index_at(int bootstrap_specifier_index) {
+    int offset = operand_offset_at(bootstrap_specifier_index);
+    return operands()->at(offset + _indy_bsm_offset);
+  }
+  int operand_argument_count_at(int bootstrap_specifier_index) {
+    int offset = operand_offset_at(bootstrap_specifier_index);
+    int argc = operands()->at(offset + _indy_argc_offset);
+    return argc;
+  }
+  int operand_argument_index_at(int bootstrap_specifier_index, int j) {
+    int offset = operand_offset_at(bootstrap_specifier_index);
+    return operands()->at(offset + _indy_argv_offset + j);
+  }
+  int operand_next_offset_at(int bootstrap_specifier_index) {
+    int offset = operand_offset_at(bootstrap_specifier_index) + _indy_argv_offset
+                   + operand_argument_count_at(bootstrap_specifier_index);
+    return offset;
+  }
+  // Compare a bootsrap specifier in the operands arrays
+  bool compare_operand_to(int bootstrap_specifier_index1, constantPoolHandle cp2,
+                          int bootstrap_specifier_index2, TRAPS);
+  // Find a bootsrap specifier in the operands array
+  int find_matching_operand(int bootstrap_specifier_index, constantPoolHandle search_cp,
+                            int operands_cur_len, TRAPS);
+  // Resize the operands array with delta_len and delta_size
+  void resize_operands(int delta_len, int delta_size, TRAPS);
+  // Extend the operands array with the length and size of the ext_cp operands
+  void extend_operands(constantPoolHandle ext_cp, TRAPS);
+  // Shrink the operands array to a smaller array with new_len length
+  void shrink_operands(int new_len, TRAPS);
+
+
   int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
     assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
     int op_base = invoke_dynamic_operand_base(which);
@@ -782,8 +822,17 @@
 
   void set_resolved_reference_length(int length) { _saved._resolved_reference_length = length; }
   int  resolved_reference_length() const  { return _saved._resolved_reference_length; }
-  void set_lock(Monitor* lock)            { _lock = lock; }
-  Monitor* lock()                         { return _lock; }
+
+  // lock() may return null -- constant pool updates may happen before this lock is
+  // initialized, because the _pool_holder has not been fully initialized and
+  // has not been registered into the system dictionary. In this case, no other
+  // thread can be modifying this constantpool, so no synchronization is
+  // necessary.
+  //
+  // Use cplock() like this:
+  //    oop cplock = cp->lock();
+  //    ObjectLocker ol(cplock , THREAD, cplock != NULL);
+  oop lock();
 
   // Decrease ref counts of symbols that are in the constant pool
   // when the holder class is unloaded
--- a/hotspot/src/share/vm/oops/cpCache.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/cpCache.cpp	Thu May 16 11:47:51 2013 +0100
@@ -266,7 +266,8 @@
   // the lock, so that when the losing writer returns, he can use the linked
   // cache entry.
 
-  MonitorLockerEx ml(cpool->lock());
+  oop cplock = cpool->lock();
+  ObjectLocker ol(cplock, Thread::current(), cplock != NULL);
   if (!is_f1_null()) {
     return;
   }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Thu May 16 11:47:51 2013 +0100
@@ -54,6 +54,7 @@
 #include "runtime/javaCalls.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/thread.inline.hpp"
+#include "services/classLoadingService.hpp"
 #include "services/threadService.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
@@ -418,25 +419,6 @@
   set_annotations(NULL);
 }
 
-volatile oop InstanceKlass::init_lock() const {
-  volatile oop lock = _init_lock;  // read once
-  assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state
-         "only fully initialized state can have a null lock");
-  return lock;
-}
-
-// Set the initialization lock to null so the object can be GC'ed.  Any racing
-// threads to get this lock will see a null lock and will not lock.
-// That's okay because they all check for initialized state after getting
-// the lock and return.
-void InstanceKlass::fence_and_clear_init_lock() {
-  // make sure previous stores are all done, notably the init_state.
-  OrderAccess::storestore();
-  klass_oop_store(&_init_lock, NULL);
-  assert(!is_not_initialized(), "class must be initialized now");
-}
-
-
 bool InstanceKlass::should_be_initialized() const {
   return !is_initialized();
 }
@@ -473,7 +455,7 @@
 void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) {
   EXCEPTION_MARK;
   volatile oop init_lock = this_oop->init_lock();
-  ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+  ObjectLocker ol(init_lock, THREAD);
 
   // abort if someone beat us to the initialization
   if (!this_oop->is_not_initialized()) return;  // note: not equivalent to is_initialized()
@@ -492,7 +474,6 @@
   } else {
     // linking successfull, mark class as initialized
     this_oop->set_init_state (fully_initialized);
-    this_oop->fence_and_clear_init_lock();
     // trace
     if (TraceClassInitialization) {
       ResourceMark rm(THREAD);
@@ -619,7 +600,7 @@
   // verification & rewriting
   {
     volatile oop init_lock = this_oop->init_lock();
-    ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+    ObjectLocker ol(init_lock, THREAD);
     // rewritten will have been set if loader constraint error found
     // on an earlier link attempt
     // don't verify or rewrite if already rewritten
@@ -742,7 +723,7 @@
   // Step 1
   {
     volatile oop init_lock = this_oop->init_lock();
-    ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+    ObjectLocker ol(init_lock, THREAD);
 
     Thread *self = THREAD; // it's passed the current thread
 
@@ -890,9 +871,8 @@
 
 void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) {
   volatile oop init_lock = this_oop->init_lock();
-  ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
+  ObjectLocker ol(init_lock, THREAD);
   this_oop->set_init_state(state);
-  this_oop->fence_and_clear_init_lock();
   ol.notify_all(CHECK);
 }
 
@@ -2312,7 +2292,29 @@
   m->clear_all_breakpoints();
 }
 
+
+void InstanceKlass::notify_unload_class(InstanceKlass* ik) {
+  // notify the debugger
+  if (JvmtiExport::should_post_class_unload()) {
+    JvmtiExport::post_class_unload(ik);
+  }
+
+  // notify ClassLoadingService of class unload
+  ClassLoadingService::notify_class_unloaded(ik);
+}
+
+void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) {
+  // Clean up C heap
+  ik->release_C_heap_structures();
+  ik->constants()->release_C_heap_structures();
+}
+
 void InstanceKlass::release_C_heap_structures() {
+
+  // Can't release the constant pool here because the constant pool can be
+  // deallocated separately from the InstanceKlass for default methods and
+  // redefine classes.
+
   // Deallocate oop map cache
   if (_oop_map_cache != NULL) {
     delete _oop_map_cache;
@@ -2837,7 +2839,7 @@
   st->print(BULLET"protection domain: "); ((InstanceKlass*)this)->protection_domain()->print_value_on(st); st->cr();
   st->print(BULLET"host class:        "); host_klass()->print_value_on_maybe_null(st); st->cr();
   st->print(BULLET"signers:           "); signers()->print_value_on(st);               st->cr();
-  st->print(BULLET"init_lock:         "); ((oop)_init_lock)->print_value_on(st);             st->cr();
+  st->print(BULLET"init_lock:         "); ((oop)_init_lock)->print_value_on(st);       st->cr();
   if (source_file_name() != NULL) {
     st->print(BULLET"source file:       ");
     source_file_name()->print_value_on(st);
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Thu May 16 11:47:51 2013 +0100
@@ -184,8 +184,9 @@
   oop             _protection_domain;
   // Class signers.
   objArrayOop     _signers;
-  // Initialization lock.  Must be one per class and it has to be a VM internal
-  // object so java code cannot lock it (like the mirror)
+  // Lock for (1) initialization; (2) access to the ConstantPool of this class.
+  // Must be one per class and it has to be a VM internal object so java code
+  // cannot lock it (like the mirror).
   // It has to be an object not a Mutex because it's held through java calls.
   volatile oop    _init_lock;
 
@@ -236,7 +237,7 @@
     _misc_rewritten            = 1 << 0, // methods rewritten.
     _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops
     _misc_should_verify_class  = 1 << 2, // allow caching of preverification
-    _misc_is_anonymous         = 1 << 3, // has embedded _inner_classes field
+    _misc_is_anonymous         = 1 << 3, // has embedded _host_klass field
     _misc_is_contended         = 1 << 4, // marked with contended annotation
     _misc_has_default_methods  = 1 << 5  // class/superclass/implemented interfaces has default methods
   };
@@ -934,7 +935,9 @@
   // referenced by handles.
   bool on_stack() const { return _constants->on_stack(); }
 
-  void release_C_heap_structures();
+  // callbacks for actions during class unloading
+  static void notify_unload_class(InstanceKlass* ik);
+  static void release_C_heap_structures(InstanceKlass* ik);
 
   // Parallel Scavenge and Parallel Old
   PARALLEL_GC_DECLS
@@ -968,6 +971,7 @@
 #endif // INCLUDE_ALL_GCS
 
   u2 idnum_allocated_count() const      { return _idnum_allocated_count; }
+
 private:
   // initialization state
 #ifdef ASSERT
@@ -994,9 +998,10 @@
          { OrderAccess::release_store_ptr(&_methods_cached_itable_indices, indices); }
 
   // Lock during initialization
-  volatile oop init_lock() const;
-  void set_init_lock(oop value)      { klass_oop_store(&_init_lock, value); }
-  void fence_and_clear_init_lock();  // after fully_initialized
+public:
+  volatile oop init_lock() const     {return _init_lock; }
+private:
+  void set_init_lock(oop value) { klass_oop_store(&_init_lock, value); }
 
   // Offsets for memory management
   oop* adr_protection_domain() const { return (oop*)&this->_protection_domain;}
@@ -1022,6 +1027,8 @@
   // Returns the array class with this class as element type
   Klass* array_klass_impl(bool or_null, TRAPS);
 
+  // Free CHeap allocated fields.
+  void release_C_heap_structures();
 public:
   // CDS support - remove and restore oops from metadata. Oops are not shared.
   virtual void remove_unshareable_info();
--- a/hotspot/src/share/vm/oops/klassVtable.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp	Thu May 16 11:47:51 2013 +0100
@@ -519,6 +519,9 @@
 // check if a method is a miranda method, given a class's methods table and it's super
 // the caller must make sure that the method belongs to an interface implemented by the class
 bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
+  if (m->is_static()) {
+    return false;
+  }
   Symbol* name = m->name();
   Symbol* signature = m->signature();
   if (InstanceKlass::find_method(class_methods, name, signature) == NULL) {
--- a/hotspot/src/share/vm/oops/method.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/method.cpp	Thu May 16 11:47:51 2013 +0100
@@ -877,7 +877,7 @@
   debug_only(No_Safepoint_Verifier nsv;)
   nmethod *code = (nmethod *)OrderAccess::load_ptr_acquire(&_code);
   if (code == NULL && UseCodeCacheFlushing) {
-    nmethod *saved_code = CodeCache::find_and_remove_saved_code(this);
+    nmethod *saved_code = CodeCache::reanimate_saved_code(this);
     if (saved_code != NULL) {
       methodHandle method(this);
       assert( ! saved_code->is_osr_method(), "should not get here for osr" );
--- a/hotspot/src/share/vm/oops/method.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/method.hpp	Thu May 16 11:47:51 2013 +0100
@@ -67,7 +67,7 @@
 // | ConstMethod*                   (oop)                 |
 // |------------------------------------------------------|
 // | methodData                     (oop)                 |
-// | interp_invocation_count                              |
+// | methodCounters                                       |
 // |------------------------------------------------------|
 // | access_flags                                         |
 // | vtable_index                                         |
@@ -76,16 +76,6 @@
 // |------------------------------------------------------|
 // | method_size             |   intrinsic_id|   flags    |
 // |------------------------------------------------------|
-// | throwout_count          |   num_breakpoints          |
-// |------------------------------------------------------|
-// | invocation_counter                                   |
-// | backedge_counter                                     |
-// |------------------------------------------------------|
-// |           prev_time (tiered only, 64 bit wide)       |
-// |                                                      |
-// |------------------------------------------------------|
-// |                  rate (tiered)                       |
-// |------------------------------------------------------|
 // | code                           (pointer)             |
 // | i2i                            (pointer)             |
 // | adapter                        (pointer)             |
--- a/hotspot/src/share/vm/oops/oop.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/oops/oop.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,11 +103,17 @@
 
 // When String table needs to rehash
 unsigned int oopDesc::new_hash(jint seed) {
+  EXCEPTION_MARK;
   ResourceMark rm;
   int length;
-  jchar* chars = java_lang_String::as_unicode_string(this, length);
-  // Use alternate hashing algorithm on the string
-  return AltHashing::murmur3_32(seed, chars, length);
+  jchar* chars = java_lang_String::as_unicode_string(this, length, THREAD);
+  if (chars != NULL) {
+    // Use alternate hashing algorithm on the string
+    return AltHashing::murmur3_32(seed, chars, length);
+  } else {
+    vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "unable to create Unicode strings for String table rehash");
+    return 0;
+  }
 }
 
 VerifyOopClosure VerifyOopClosure::verify_oop;
--- a/hotspot/src/share/vm/opto/graphKit.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.cpp	Thu May 16 11:47:51 2013 +0100
@@ -3564,7 +3564,8 @@
 
   Node* no_ctrl = NULL;
   Node* no_base = __ top();
-  Node* zero = __ ConI(0);
+  Node* zero  = __ ConI(0);
+  Node* zeroX = __ ConX(0);
 
   float likely  = PROB_LIKELY(0.999);
   float unlikely  = PROB_UNLIKELY(0.999);
@@ -3590,7 +3591,9 @@
 
   // if (!marking)
   __ if_then(marking, BoolTest::ne, zero); {
-    Node* index   = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
+    BasicType index_bt = TypeX_X->basic_type();
+    assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 PtrQueue::_index with wrong size.");
+    Node* index   = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw);
 
     if (do_load) {
       // load original value
@@ -3603,22 +3606,16 @@
       Node* buffer  = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
 
       // is the queue for this thread full?
-      __ if_then(index, BoolTest::ne, zero, likely); {
+      __ if_then(index, BoolTest::ne, zeroX, likely); {
 
         // decrement the index
-        Node* next_index = __ SubI(index,  __ ConI(sizeof(intptr_t)));
-        Node* next_indexX = next_index;
-#ifdef _LP64
-        // We could refine the type for what it's worth
-        // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue);
-        next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) );
-#endif
+        Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t))));
 
         // Now get the buffer location we will log the previous value into and store it
-        Node *log_addr = __ AddP(no_base, buffer, next_indexX);
+        Node *log_addr = __ AddP(no_base, buffer, next_index);
         __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw);
         // update the index
-        __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw);
+        __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw);
 
       } __ else_(); {
 
@@ -3645,26 +3642,21 @@
                             Node* buffer,
                             const TypeFunc* tf) {
 
-  Node* zero = __ ConI(0);
+  Node* zero  = __ ConI(0);
+  Node* zeroX = __ ConX(0);
   Node* no_base = __ top();
   BasicType card_bt = T_BYTE;
   // Smash zero into card. MUST BE ORDERED WRT TO STORE
   __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw);
 
   //  Now do the queue work
-  __ if_then(index, BoolTest::ne, zero); {
-
-    Node* next_index = __ SubI(index, __ ConI(sizeof(intptr_t)));
-    Node* next_indexX = next_index;
-#ifdef _LP64
-    // We could refine the type for what it's worth
-    // const TypeLong* lidxtype = TypeLong::make(CONST64(0), get_size_from_queue);
-    next_indexX = _gvn.transform( new (C) ConvI2LNode(next_index, TypeLong::make(0, max_jlong, Type::WidenMax)) );
-#endif // _LP64
-    Node* log_addr = __ AddP(no_base, buffer, next_indexX);
+  __ if_then(index, BoolTest::ne, zeroX); {
+
+    Node* next_index = _gvn.transform(new (C) SubXNode(index, __ ConX(sizeof(intptr_t))));
+    Node* log_addr = __ AddP(no_base, buffer, next_index);
 
     __ store(__ ctrl(), log_addr, card_adr, T_ADDRESS, Compile::AliasIdxRaw);
-    __ store(__ ctrl(), index_adr, next_index, T_INT, Compile::AliasIdxRaw);
+    __ store(__ ctrl(), index_adr, next_index, TypeX_X->basic_type(), Compile::AliasIdxRaw);
 
   } __ else_(); {
     __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), "g1_wb_post", card_adr, __ thread());
@@ -3725,7 +3717,7 @@
   // Now some values
   // Use ctrl to avoid hoisting these values past a safepoint, which could
   // potentially reset these fields in the JavaThread.
-  Node* index  = __ load(__ ctrl(), index_adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw);
+  Node* index  = __ load(__ ctrl(), index_adr, TypeX_X, TypeX_X->basic_type(), Compile::AliasIdxRaw);
   Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw);
 
   // Convert the store obj pointer to an int prior to doing math on it
--- a/hotspot/src/share/vm/opto/output.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/opto/output.cpp	Thu May 16 11:47:51 2013 +0100
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "asm/assembler.inline.hpp"
+#include "code/compiledIC.hpp"
 #include "code/debugInfo.hpp"
 #include "code/debugInfoRec.hpp"
 #include "compiler/compileBroker.hpp"
@@ -41,8 +42,6 @@
 #include "runtime/handles.inline.hpp"
 #include "utilities/xmlstream.hpp"
 
-extern uint size_java_to_interp();
-extern uint reloc_java_to_interp();
 extern uint size_exception_handler();
 extern uint size_deopt_handler();
 
@@ -389,15 +388,15 @@
         MachNode *mach = nj->as_Mach();
         blk_size += (mach->alignment_required() - 1) * relocInfo::addr_unit(); // assume worst case padding
         reloc_size += mach->reloc();
-        if( mach->is_MachCall() ) {
+        if (mach->is_MachCall()) {
           MachCallNode *mcall = mach->as_MachCall();
           // This destination address is NOT PC-relative
 
           mcall->method_set((intptr_t)mcall->entry_point());
 
-          if( mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method ) {
-            stub_size  += size_java_to_interp();
-            reloc_size += reloc_java_to_interp();
+          if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
+            stub_size  += CompiledStaticCall::to_interp_stub_size();
+            reloc_size += CompiledStaticCall::reloc_to_interp_stub();
           }
         } else if (mach->is_MachSafePoint()) {
           // If call/safepoint are adjacent, account for possible
--- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.cpp	Thu May 16 11:47:51 2013 +0100
@@ -341,6 +341,44 @@
   memcpy(writeable_address(length), annos->adr_at(0), length);
 }
 
+//  BootstrapMethods_attribute {
+//    u2 attribute_name_index;
+//    u4 attribute_length;
+//    u2 num_bootstrap_methods;
+//    {   u2 bootstrap_method_ref;
+//        u2 num_bootstrap_arguments;
+//        u2 bootstrap_arguments[num_bootstrap_arguments];
+//    } bootstrap_methods[num_bootstrap_methods];
+//  }
+void JvmtiClassFileReconstituter::write_bootstrapmethod_attribute() {
+  Array<u2>* operands = cpool()->operands();
+  write_attribute_name_index("BootstrapMethods");
+  int num_bootstrap_methods = ConstantPool::operand_array_length(operands);
+
+  // calculate length of attribute
+  int length = sizeof(u2); // num_bootstrap_methods
+  for (int n = 0; n < num_bootstrap_methods; n++) {
+    u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n);
+    length += sizeof(u2); // bootstrap_method_ref
+    length += sizeof(u2); // num_bootstrap_arguments
+    length += sizeof(u2) * num_bootstrap_arguments; // bootstrap_arguments[num_bootstrap_arguments]
+  }
+  write_u4(length);
+
+  // write attribute
+  write_u2(num_bootstrap_methods);
+  for (int n = 0; n < num_bootstrap_methods; n++) {
+    u2 bootstrap_method_ref = cpool()->operand_bootstrap_method_ref_index_at(n);
+    u2 num_bootstrap_arguments = cpool()->operand_argument_count_at(n);
+    write_u2(bootstrap_method_ref);
+    write_u2(num_bootstrap_arguments);
+    for (int arg = 0; arg < num_bootstrap_arguments; arg++) {
+      u2 bootstrap_argument = cpool()->operand_argument_index_at(n, arg);
+      write_u2(bootstrap_argument);
+    }
+  }
+}
+
 
 // Write InnerClasses attribute
 // JVMSpec|   InnerClasses_attribute {
@@ -513,6 +551,11 @@
   AnnotationArray* param_anno = method->parameter_annotations();
   AnnotationArray* default_anno = method->annotation_default();
 
+  // skip generated default interface methods
+  if (method->is_overpass()) {
+    return;
+  }
+
   write_u2(access_flags.get_flags() & JVM_RECOGNIZED_METHOD_MODIFIERS);
   write_u2(const_method->name_index());
   write_u2(const_method->signature_index());
@@ -592,6 +635,9 @@
   if (anno != NULL) {
     ++attr_count;     // has RuntimeVisibleAnnotations attribute
   }
+  if (cpool()->operands() != NULL) {
+    ++attr_count;
+  }
 
   write_u2(attr_count);
 
@@ -610,6 +656,9 @@
   if (anno != NULL) {
     write_annotations_attribute("RuntimeVisibleAnnotations", anno);
   }
+  if (cpool()->operands() != NULL) {
+    write_bootstrapmethod_attribute();
+  }
 }
 
 // Write the method information portion of ClassFile structure
@@ -619,8 +668,19 @@
   HandleMark hm(thread());
   Array<Method*>* methods = ikh()->methods();
   int num_methods = methods->length();
+  int num_overpass = 0;
 
-  write_u2(num_methods);
+  // count the generated default interface methods
+  // these will not be re-created by write_method_info
+  // and should not be included in the total count
+  for (int index = 0; index < num_methods; index++) {
+    Method* method = methods->at(index);
+    if (method->is_overpass()) {
+      num_overpass++;
+    }
+  }
+
+  write_u2(num_methods - num_overpass);
   if (JvmtiExport::can_maintain_original_method_order()) {
     int index;
     int original_index;
--- a/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiClassFileReconstituter.hpp	Thu May 16 11:47:51 2013 +0100
@@ -127,6 +127,7 @@
   void write_signature_attribute(u2 generic_signaure_index);
   void write_attribute_name_index(const char* name);
   void write_annotations_attribute(const char* attr_name, AnnotationArray* annos);
+  void write_bootstrapmethod_attribute();
 
   address writeable_address(size_t size);
   void write_u1(u1 x);
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp	Thu May 16 11:47:51 2013 +0100
@@ -259,7 +259,8 @@
       // bytes to the InstanceKlass here because they have not been
       // validated and we're not at a safepoint.
       constantPoolHandle  constants(current_thread, ikh->constants());
-      MonitorLockerEx ml(constants->lock());    // lock constant pool while we query it
+      oop cplock = constants->lock();
+      ObjectLocker ol(cplock, current_thread, cplock != NULL);    // lock constant pool while we query it
 
       JvmtiClassFileReconstituter reconstituter(ikh);
       if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
@@ -2417,7 +2418,8 @@
 
   instanceKlassHandle ikh(thread, k_oop);
   constantPoolHandle  constants(thread, ikh->constants());
-  MonitorLockerEx ml(constants->lock());    // lock constant pool while we query it
+  oop cplock = constants->lock();
+  ObjectLocker ol(cplock, thread, cplock != NULL);    // lock constant pool while we query it
 
   JvmtiConstantPoolReconstituter reconstituter(ikh);
   if (reconstituter.get_error() != JVMTI_ERROR_NONE) {
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp	Thu May 16 11:47:51 2013 +0100
@@ -415,20 +415,26 @@
     // this is an indirect CP entry so it needs special handling
     case JVM_CONSTANT_InvokeDynamic:
     {
-      // TBD: cross-checks and possible extra appends into CP and bsm operands
-      // are needed as well. This issue is tracked by a separate bug 8007037.
-      int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
-
-      int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
-      int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+      // Index of the bootstrap specifier in the operands array
+      int old_bs_i = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
+      int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p,
+                                            merge_cp_length_p, THREAD);
+      // The bootstrap method NameAndType_info index
+      int old_ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
+      int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
                                                     merge_cp_length_p, THREAD);
-      if (new_ref_i != ref_i) {
+      if (new_bs_i != old_bs_i) {
         RC_TRACE(0x00080000,
-                 ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d",
-                  *merge_cp_length_p, ref_i, new_ref_i));
+                 ("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d",
+                  *merge_cp_length_p, old_bs_i, new_bs_i));
       }
-
-      (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i);
+      if (new_ref_i != old_ref_i) {
+        RC_TRACE(0x00080000,
+                 ("InvokeDynamic entry@%d name_and_type_index change: %d to %d",
+                  *merge_cp_length_p, old_ref_i, new_ref_i));
+      }
+
+      (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
       if (scratch_i != *merge_cp_length_p) {
         // The new entry in *merge_cp_p is at a different index than
         // the new entry in scratch_cp so we need to map the index values.
@@ -492,6 +498,105 @@
 } // end find_or_append_indirect_entry()
 
 
+// Append a bootstrap specifier into the merge_cp operands that is semantically equal
+// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index.
+// Recursively append new merge_cp entries referenced by the new bootstrap specifier.
+void VM_RedefineClasses::append_operand(constantPoolHandle scratch_cp, int old_bs_i,
+       constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+
+  int old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i);
+  int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
+                                                merge_cp_length_p, THREAD);
+  if (new_ref_i != old_ref_i) {
+    RC_TRACE(0x00080000,
+             ("operands entry@%d bootstrap method ref_index change: %d to %d",
+              _operands_cur_length, old_ref_i, new_ref_i));
+  }
+
+  Array<u2>* merge_ops = (*merge_cp_p)->operands();
+  int new_bs_i = _operands_cur_length;
+  // We have _operands_cur_length == 0 when the merge_cp operands is empty yet.
+  // However, the operand_offset_at(0) was set in the extend_operands() call.
+  int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0)
+                                 : (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1);
+  int argc     = scratch_cp->operand_argument_count_at(old_bs_i);
+
+  ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base);
+  merge_ops->at_put(new_base++, new_ref_i);
+  merge_ops->at_put(new_base++, argc);
+
+  for (int i = 0; i < argc; i++) {
+    int old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i);
+    int new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p,
+                                                      merge_cp_length_p, THREAD);
+    merge_ops->at_put(new_base++, new_arg_ref_i);
+    if (new_arg_ref_i != old_arg_ref_i) {
+      RC_TRACE(0x00080000,
+               ("operands entry@%d bootstrap method argument ref_index change: %d to %d",
+                _operands_cur_length, old_arg_ref_i, new_arg_ref_i));
+    }
+  }
+  if (old_bs_i != _operands_cur_length) {
+    // The bootstrap specifier in *merge_cp_p is at a different index than
+    // that in scratch_cp so we need to map the index values.
+    map_operand_index(old_bs_i, new_bs_i);
+  }
+  _operands_cur_length++;
+} // end append_operand()
+
+
+int VM_RedefineClasses::find_or_append_operand(constantPoolHandle scratch_cp,
+      int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+
+  int new_bs_i = old_bs_i; // bootstrap specifier index
+  bool match = (old_bs_i < _operands_cur_length) &&
+               scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i, THREAD);
+
+  if (!match) {
+    // forward reference in *merge_cp_p or not a direct match
+    int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p,
+                                                    _operands_cur_length, THREAD);
+    if (found_i != -1) {
+      guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree");
+      // found a matching operand somewhere else in *merge_cp_p so just need a mapping
+      new_bs_i = found_i;
+      map_operand_index(old_bs_i, found_i);
+    } else {
+      // no match found so we have to append this bootstrap specifier to *merge_cp_p
+      append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p, THREAD);
+      new_bs_i = _operands_cur_length - 1;
+    }
+  }
+  return new_bs_i;
+} // end find_or_append_operand()
+
+
+void VM_RedefineClasses::finalize_operands_merge(constantPoolHandle merge_cp, TRAPS) {
+  if (merge_cp->operands() == NULL) {
+    return;
+  }
+  // Shrink the merge_cp operands
+  merge_cp->shrink_operands(_operands_cur_length, CHECK);
+
+  if (RC_TRACE_ENABLED(0x00040000)) {
+    // don't want to loop unless we are tracing
+    int count = 0;
+    for (int i = 1; i < _operands_index_map_p->length(); i++) {
+      int value = _operands_index_map_p->at(i);
+      if (value != -1) {
+        RC_TRACE_WITH_THREAD(0x00040000, THREAD,
+          ("operands_index_map[%d]: old=%d new=%d", count, i, value));
+        count++;
+      }
+    }
+  }
+  // Clean-up
+  _operands_index_map_p = NULL;
+  _operands_cur_length = 0;
+  _operands_index_map_count = 0;
+} // end finalize_operands_merge()
+
+
 jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
              instanceKlassHandle the_class,
              instanceKlassHandle scratch_class) {
@@ -765,6 +870,31 @@
 } // end find_new_index()
 
 
+// Find new bootstrap specifier index value for old bootstrap specifier index
+// value by seaching the index map. Returns unused index (-1) if there is
+// no mapped value for the old bootstrap specifier index.
+int VM_RedefineClasses::find_new_operand_index(int old_index) {
+  if (_operands_index_map_count == 0) {
+    // map is empty so nothing can be found
+    return -1;
+  }
+
+  if (old_index == -1 || old_index >= _operands_index_map_p->length()) {
+    // The old_index is out of range so it is not mapped.
+    // This should not happen in regular constant pool merging use.
+    return -1;
+  }
+
+  int value = _operands_index_map_p->at(old_index);
+  if (value == -1) {
+    // the old_index is not mapped
+    return -1;
+  }
+
+  return value;
+} // end find_new_operand_index()
+
+
 // Returns true if the current mismatch is due to a resolved/unresolved
 // class pair. Otherwise, returns false.
 bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1,
@@ -1014,6 +1144,25 @@
 } // end map_index()
 
 
+// Map old_index to new_index as needed.
+void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
+  if (find_new_operand_index(old_index) != -1) {
+    // old_index is already mapped
+    return;
+  }
+
+  if (old_index == new_index) {
+    // no mapping is needed
+    return;
+  }
+
+  _operands_index_map_p->at_put(old_index, new_index);
+  _operands_index_map_count++;
+
+  RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", old_index, new_index));
+} // end map_index()
+
+
 // Merge old_cp and scratch_cp and return the results of the merge via
 // merge_cp_p. The number of entries in *merge_cp_p is returned via
 // merge_cp_length_p. The entries in old_cp occupy the same locations
@@ -1086,6 +1235,7 @@
     } // end for each old_cp entry
 
     ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0);
+    (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
 
     // We don't need to sanity check that *merge_cp_length_p is within
     // *merge_cp_p bounds since we have the minimum on-entry check above.
@@ -1198,6 +1348,8 @@
         CHECK_0);
     }
 
+    finalize_operands_merge(*merge_cp_p, THREAD);
+
     RC_TRACE_WITH_THREAD(0x00020000, THREAD,
       ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
       *merge_cp_length_p, scratch_i, _index_map_count));
@@ -1270,6 +1422,11 @@
   _index_map_count = 0;
   _index_map_p = new intArray(scratch_cp->length(), -1);
 
+  _operands_cur_length = ConstantPool::operand_array_length(old_cp->operands());
+  _operands_index_map_count = 0;
+  _operands_index_map_p = new intArray(
+    ConstantPool::operand_array_length(scratch_cp->operands()), -1);
+
   // reference to the cp holder is needed for copy_operands()
   merge_cp->set_pool_holder(scratch_class());
   bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
@@ -1400,7 +1557,6 @@
   return true;
 } // end rewrite_cp_refs()
 
-
 // Rewrite constant pool references in the methods.
 bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
        instanceKlassHandle scratch_class, TRAPS) {
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp	Thu May 16 11:47:51 2013 +0100
@@ -359,8 +359,15 @@
   // _index_map_p contains any entries.
   int                         _index_map_count;
   intArray *                  _index_map_p;
+
+  // _operands_index_map_count is just an optimization for knowing if
+  // _operands_index_map_p contains any entries.
+  int                         _operands_cur_length;
+  int                         _operands_index_map_count;
+  intArray *                  _operands_index_map_p;
+
   // ptr to _class_count scratch_classes
-  Klass**                   _scratch_classes;
+  Klass**                     _scratch_classes;
   jvmtiError                  _res;
 
   // Performance measurement support. These timers do not cover all
@@ -422,12 +429,19 @@
   // Support for constant pool merging (these routines are in alpha order):
   void append_entry(constantPoolHandle scratch_cp, int scratch_i,
     constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+  void append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+    constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+  void finalize_operands_merge(constantPoolHandle merge_cp, TRAPS);
   int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i,
     constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+  int find_or_append_operand(constantPoolHandle scratch_cp, int scratch_bootstrap_spec_index,
+    constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
   int find_new_index(int old_index);
+  int find_new_operand_index(int old_bootstrap_spec_index);
   bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1,
     constantPoolHandle cp2, int index2);
   void map_index(constantPoolHandle scratch_cp, int old_index, int new_index);
+  void map_operand_index(int old_bootstrap_spec_index, int new_bootstrap_spec_index);
   bool merge_constant_pools(constantPoolHandle old_cp,
     constantPoolHandle scratch_cp, constantPoolHandle *merge_cp_p,
     int *merge_cp_length_p, TRAPS);
--- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp	Thu May 16 11:47:51 2013 +0100
@@ -153,7 +153,8 @@
     size_t s = initial_size * sizeof(JvmtiTagHashmapEntry*);
     _table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
     if (_table == NULL) {
-      vm_exit_out_of_memory(s, "unable to allocate initial hashtable for jvmti object tags");
+      vm_exit_out_of_memory(s, OOM_MALLOC_ERROR,
+        "unable to allocate initial hashtable for jvmti object tags");
     }
     for (int i=0; i<initial_size; i++) {
       _table[i] = NULL;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp	Thu May 16 11:47:51 2013 +0100
@@ -67,7 +67,8 @@
   TraceTime timer("MethodHandles adapters generation", TraceStartupTime);
   _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size);
   if (_adapter_code == NULL)
-    vm_exit_out_of_memory(adapter_code_size, "CodeCache: no room for MethodHandles adapters");
+    vm_exit_out_of_memory(adapter_code_size, OOM_MALLOC_ERROR,
+                          "CodeCache: no room for MethodHandles adapters");
   {
     CodeBuffer code(_adapter_code);
     MethodHandlesAdapterGenerator g(&code);
--- a/hotspot/src/share/vm/prims/perf.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/perf.cpp	Thu May 16 11:47:51 2013 +0100
@@ -142,20 +142,20 @@
   }
 
   switch(variability) {
-  case 1:  /* V_Constant */
+  case PerfData::V_Constant:
     pl = PerfDataManager::create_long_constant(NULL_NS, (char *)name_utf,
                                                (PerfData::Units)units, value,
                                                CHECK_NULL);
     break;
 
-  case 2:  /* V_Variable */
-    pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
+  case PerfData::V_Monotonic:
+    pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
                                                (PerfData::Units)units, value,
                                                CHECK_NULL);
     break;
 
-  case 3:  /* V_Monotonic Counter */
-    pl = PerfDataManager::create_long_counter(NULL_NS, (char *)name_utf,
+  case PerfData::V_Variable:
+    pl = PerfDataManager::create_long_variable(NULL_NS, (char *)name_utf,
                                               (PerfData::Units)units, value,
                                               CHECK_NULL);
     break;
--- a/hotspot/src/share/vm/prims/unsafe.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/unsafe.cpp	Thu May 16 11:47:51 2013 +0100
@@ -315,10 +315,7 @@
   OrderAccess::fence();
 UNSAFE_END
 
-#if defined(SPARC) || defined(X86)
-// Sparc and X86 have atomic jlong (8 bytes) instructions
-
-#else
+#ifndef SUPPORTS_NATIVE_CX8
 // Keep old code for platforms which may not have atomic jlong (8 bytes) instructions
 
 // Volatile long versions must use locks if !VM_Version::supports_cx8().
@@ -356,7 +353,7 @@
   }
 UNSAFE_END
 
-#endif // not SPARC and not X86
+#endif // not SUPPORTS_NATIVE_CX8
 
 #define DEFINE_GETSETOOP(jboolean, Boolean) \
  \
@@ -420,8 +417,7 @@
 DEFINE_GETSETOOP_VOLATILE(jfloat, Float);
 DEFINE_GETSETOOP_VOLATILE(jdouble, Double);
 
-#if defined(SPARC) || defined(X86)
-// Sparc and X86 have atomic jlong (8 bytes) instructions
+#ifdef SUPPORTS_NATIVE_CX8
 DEFINE_GETSETOOP_VOLATILE(jlong, Long);
 #endif
 
@@ -450,8 +446,7 @@
 
 UNSAFE_ENTRY(void, Unsafe_SetOrderedLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong x))
   UnsafeWrapper("Unsafe_SetOrderedLong");
-#if defined(SPARC) || defined(X86)
-  // Sparc and X86 have atomic jlong (8 bytes) instructions
+#ifdef SUPPORTS_NATIVE_CX8
   SET_FIELD_VOLATILE(obj, offset, jlong, x);
 #else
   // Keep old code for platforms which may not have atomic long (8 bytes) instructions
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,6 +93,15 @@
   return closure.found();
 WB_END
 
+WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) {
+  CollectorPolicy * p = Universe::heap()->collector_policy();
+  gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap "
+    SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT,
+    p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(),
+    p->min_alignment(), p->max_alignment());
+}
+WB_END
+
 #if INCLUDE_ALL_GCS
 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
   G1CollectedHeap* g1 = G1CollectedHeap::heap();
@@ -310,12 +319,8 @@
 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
   ResourceMark rm(THREAD);
   int len;
-  jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len);
-  oop found_string = StringTable::the_table()->lookup(name, len);
-  if (found_string == NULL) {
-        return false;
-  }
-  return true;
+  jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len, CHECK_false);
+  return (StringTable::lookup(name, len) != NULL);
 WB_END
 
 
@@ -324,6 +329,11 @@
   Universe::heap()->collect(GCCause::_last_ditch_collection);
 WB_END
 
+
+WB_ENTRY(jlong, WB_ReserveMemory(JNIEnv* env, jobject o, jlong size))
+  return (jlong)os::reserve_memory(size, NULL, 0);
+WB_END
+
 //Some convenience methods to deal with objects from java
 int WhiteBox::offset_for_field(const char* field_name, oop object,
     Symbol* signature_symbol) {
@@ -385,6 +395,7 @@
       CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
       (void*) &WB_ParseCommandLine
   },
+  {CC"printHeapSizes",     CC"()V",                   (void*)&WB_PrintHeapSizes    },
 #if INCLUDE_ALL_GCS
   {CC"g1InConcurrentMark", CC"()Z",                   (void*)&WB_G1InConcurrentMark},
   {CC"g1IsHumongous",      CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous     },
@@ -425,6 +436,8 @@
       CC"(Ljava/lang/reflect/Executable;)V",          (void*)&WB_ClearMethodState},
   {CC"isInStringTable",   CC"(Ljava/lang/String;)Z",  (void*)&WB_IsInStringTable  },
   {CC"fullGC",   CC"()V",                             (void*)&WB_FullGC },
+
+  {CC"reserveMemory", CC"(J)J", (void*)&WB_ReserveMemory },
 };
 
 #undef CC
@@ -436,9 +449,29 @@
       instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
       Handle loader(ikh->class_loader());
       if (loader.is_null()) {
+        ResourceMark rm;
         ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
-        jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0]));
-        if (result == 0) {
+        bool result = true;
+        //  one by one registration natives for exception catching
+        jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string());
+        for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) {
+          if (env->RegisterNatives(wbclass, methods + i, 1) != 0) {
+            result = false;
+            if (env->ExceptionCheck() && env->IsInstanceOf(env->ExceptionOccurred(), exceptionKlass)) {
+              // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native
+              // ignoring the exception
+              tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature);
+              env->ExceptionClear();
+            } else {
+              // register is failed w/o exception or w/ unexpected exception
+              tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature);
+              env->UnregisterNatives(wbclass);
+              break;
+            }
+          }
+        }
+
+        if (result) {
           WhiteBox::set_used();
         }
       }
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Thu May 16 11:47:51 2013 +0100
@@ -747,16 +747,16 @@
     return;
   }
 
-  int index = *count;
+  int new_count = *count + 1;
 
   // expand the array and add arg to the last element
-  (*count)++;
   if (*bldarray == NULL) {
-    *bldarray = NEW_C_HEAP_ARRAY(char*, *count, mtInternal);
+    *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtInternal);
   } else {
-    *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, *count, mtInternal);
+    *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtInternal);
   }
-  (*bldarray)[index] = strdup(arg);
+  (*bldarray)[*count] = strdup(arg);
+  *count = new_count;
 }
 
 void Arguments::build_jvm_args(const char* arg) {
@@ -1617,30 +1617,38 @@
     FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx)reasonable_max);
   }
 
-  // If the initial_heap_size has not been set with InitialHeapSize
-  // or -Xms, then set it as fraction of the size of physical memory,
-  // respecting the maximum and minimum sizes of the heap.
-  if (FLAG_IS_DEFAULT(InitialHeapSize)) {
+  // If the minimum or initial heap_size have not been set or requested to be set
+  // ergonomically, set them accordingly.
+  if (InitialHeapSize == 0 || min_heap_size() == 0) {
     julong reasonable_minimum = (julong)(OldSize + NewSize);
 
     reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize);
 
     reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum);
 
-    julong reasonable_initial = phys_mem / InitialRAMFraction;
-
-    reasonable_initial = MAX2(reasonable_initial, reasonable_minimum);
-    reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
-
-    reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
-
-    if (PrintGCDetails && Verbose) {
-      // Cannot use gclog_or_tty yet.
-      tty->print_cr("  Initial heap size " SIZE_FORMAT, (uintx)reasonable_initial);
-      tty->print_cr("  Minimum heap size " SIZE_FORMAT, (uintx)reasonable_minimum);
+    if (InitialHeapSize == 0) {
+      julong reasonable_initial = phys_mem / InitialRAMFraction;
+
+      reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)min_heap_size());
+      reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
+
+      reasonable_initial = limit_by_allocatable_memory(reasonable_initial);
+
+      if (PrintGCDetails && Verbose) {
+        // Cannot use gclog_or_tty yet.
+        tty->print_cr("  Initial heap size " SIZE_FORMAT, (uintx)reasonable_initial);
+      }
+      FLAG_SET_ERGO(uintx, InitialHeapSize, (uintx)reasonable_initial);
     }
-    FLAG_SET_ERGO(uintx, InitialHeapSize, (uintx)reasonable_initial);
-    set_min_heap_size((uintx)reasonable_minimum);
+    // If the minimum heap size has not been set (via -Xms),
+    // synchronize with InitialHeapSize to avoid errors with the default value.
+    if (min_heap_size() == 0) {
+      set_min_heap_size(MIN2((uintx)reasonable_minimum, InitialHeapSize));
+      if (PrintGCDetails && Verbose) {
+        // Cannot use gclog_or_tty yet.
+        tty->print_cr("  Minimum heap size " SIZE_FORMAT, min_heap_size());
+      }
+    }
   }
 }
 
@@ -2043,6 +2051,10 @@
                                         "G1RefProcDrainInterval");
     status = status && verify_min_value((intx)G1ConcMarkStepDurationMillis, 1,
                                         "G1ConcMarkStepDurationMillis");
+    status = status && verify_interval(G1ConcRSHotCardLimit, 0, max_jubyte,
+                                       "G1ConcRSHotCardLimit");
+    status = status && verify_interval(G1ConcRSLogCacheSize, 0, 31,
+                                       "G1ConcRSLogCacheSize");
   }
 #endif // INCLUDE_ALL_GCS
 
@@ -2224,6 +2236,55 @@
   return JNI_OK;
 }
 
+// Checks if name in command-line argument -agent{lib,path}:name[=options]
+// represents a valid HPROF of JDWP agent.  is_path==true denotes that we
+// are dealing with -agentpath (case where name is a path), otherwise with
+// -agentlib
+bool valid_hprof_or_jdwp_agent(char *name, bool is_path) {
+  char *_name;
+  const char *_hprof = "hprof", *_jdwp = "jdwp";
+  size_t _len_hprof, _len_jdwp, _len_prefix;
+
+  if (is_path) {
+    if ((_name = strrchr(name, (int) *os::file_separator())) == NULL) {
+      return false;
+    }
+
+    _name++;  // skip past last path separator
+    _len_prefix = strlen(JNI_LIB_PREFIX);
+
+    if (strncmp(_name, JNI_LIB_PREFIX, _len_prefix) != 0) {
+      return false;
+    }
+
+    _name += _len_prefix;
+    _len_hprof = strlen(_hprof);
+    _len_jdwp = strlen(_jdwp);
+
+    if (strncmp(_name, _hprof, _len_hprof) == 0) {
+      _name += _len_hprof;
+    }
+    else if (strncmp(_name, _jdwp, _len_jdwp) == 0) {
+      _name += _len_jdwp;
+    }
+    else {
+      return false;
+    }
+
+    if (strcmp(_name, JNI_LIB_SUFFIX) != 0) {
+      return false;
+    }
+
+    return true;
+  }
+
+  if (strcmp(name, _hprof) == 0 || strcmp(name, _jdwp) == 0) {
+    return true;
+  }
+
+  return false;
+}
+
 jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
                                        SysClassPath* scp_p,
                                        bool* scp_assembly_required_p,
@@ -2322,7 +2383,7 @@
           options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1, mtInternal), pos + 1);
         }
 #if !INCLUDE_JVMTI
-        if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) {
+        if (valid_hprof_or_jdwp_agent(name, is_absolute_path)) {
           jio_fprintf(defaultStream::error_stream(),
             "Profiling and debugging agents are not supported in this VM\n");
           return JNI_ERR;
@@ -2377,7 +2438,8 @@
     // -Xms
     } else if (match_option(option, "-Xms", &tail)) {
       julong long_initial_heap_size = 0;
-      ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 1);
+      // an initial heap size of 0 means automatically determine
+      ArgsRange errcode = parse_memory_size(tail, &long_initial_heap_size, 0);
       if (errcode != arg_in_range) {
         jio_fprintf(defaultStream::error_stream(),
                     "Invalid initial heap size: %s\n", option->optionString);
@@ -2388,7 +2450,7 @@
       // Currently the minimum size and the initial heap sizes are the same.
       set_min_heap_size(InitialHeapSize);
     // -Xmx
-    } else if (match_option(option, "-Xmx", &tail)) {
+    } else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {
       julong long_max_heap_size = 0;
       ArgsRange errcode = parse_memory_size(tail, &long_max_heap_size, 1);
       if (errcode != arg_in_range) {
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Thu May 16 11:47:51 2013 +0100
@@ -109,6 +109,9 @@
 
 // Returns true if m is allowed to be compiled
 bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) {
+  // allow any levels for WhiteBox
+  assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
+
   if (m->is_abstract()) return false;
   if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
 
@@ -122,7 +125,13 @@
     return false;
   }
   if (comp_level == CompLevel_all) {
-    return !m->is_not_compilable(CompLevel_simple) && !m->is_not_compilable(CompLevel_full_optimization);
+    if (TieredCompilation) {
+      // enough to be compilable at any level for tiered
+      return !m->is_not_compilable(CompLevel_simple) || !m->is_not_compilable(CompLevel_full_optimization);
+    } else {
+      // must be compilable at available level for non-tiered
+      return !m->is_not_compilable(CompLevel_highest_tier);
+    }
   } else if (is_compile(comp_level)) {
     return !m->is_not_compilable(comp_level);
   }
@@ -436,7 +445,7 @@
   reset_counter_for_invocation_event(m);
   const char* comment = "count";
 
-  if (is_compilation_enabled() && can_be_compiled(m)) {
+  if (is_compilation_enabled() && can_be_compiled(m, comp_level)) {
     nmethod* nm = m->code();
     if (nm == NULL ) {
       CompileBroker::compile_method(m, InvocationEntryBci, comp_level, m, hot_count, comment, thread);
@@ -449,7 +458,7 @@
   const int hot_count = m->backedge_count();
   const char* comment = "backedge_count";
 
-  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
     CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
     NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
   }
@@ -467,7 +476,7 @@
   reset_counter_for_invocation_event(m);
   const char* comment = "count";
 
-  if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m)) {
+  if (is_compilation_enabled() && m->code() == NULL && can_be_compiled(m, comp_level)) {
     ResourceMark rm(thread);
     frame       fr     = thread->last_frame();
     assert(fr.is_interpreted_frame(), "must be interpreted");
@@ -505,7 +514,7 @@
   const int hot_count = m->backedge_count();
   const char* comment = "backedge_count";
 
-  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m)) {
+  if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) {
     CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread);
     NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));)
   }
@@ -600,7 +609,7 @@
 
     // If the caller method is too big or something then we do not want to
     // compile it just to inline a method
-    if (!can_be_compiled(next_m)) {
+    if (!can_be_compiled(next_m, CompLevel_any)) {
       msg = "caller cannot be compiled";
       break;
     }
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Thu May 16 11:47:51 2013 +0100
@@ -2123,6 +2123,9 @@
   product(intx, PrefetchFieldsAhead, -1,                                    \
           "How many fields ahead to prefetch in oop scan (<= 0 means off)") \
                                                                             \
+  diagnostic(bool, VerifySilently, false,                                   \
+          "Don't print print the verification progress")                    \
+                                                                            \
   diagnostic(bool, VerifyDuringStartup, false,                              \
           "Verify memory system before executing any Java code "            \
           "during VM initialization")                                       \
@@ -2965,7 +2968,7 @@
                                                                             \
   /* gc parameters */                                                       \
   product(uintx, InitialHeapSize, 0,                                        \
-          "Initial heap size (in bytes); zero means OldSize + NewSize")     \
+          "Initial heap size (in bytes); zero means use ergonomics")        \
                                                                             \
   product(uintx, MaxHeapSize, ScaleForWordSize(96*M),                       \
           "Maximum heap size (in bytes)")                                   \
@@ -3179,6 +3182,9 @@
   product(uintx,  CodeCacheFlushingMinimumFreeSpace, 1500*K,                \
           "When less than X space left, start code cache cleaning")         \
                                                                             \
+  product(uintx, CodeCacheFlushingFraction, 2,                              \
+          "Fraction of the code cache that is flushed when full")           \
+                                                                            \
   /* interpreter debugging */                                               \
   develop(intx, BinarySwitchThreshold, 5,                                   \
           "Minimal number of lookupswitch entries for rewriting to binary " \
@@ -3223,8 +3229,9 @@
   develop(bool, ReplayCompiles, false,                                      \
           "Enable replay of compilations from ReplayDataFile")              \
                                                                             \
-  develop(ccstr, ReplayDataFile, "replay.txt",                              \
-          "file containing compilation replay information")                 \
+  product(ccstr, ReplayDataFile, NULL,                                      \
+          "File containing compilation replay information"                  \
+          "[default: ./replay_pid%p.log] (%p replaced with pid)")           \
                                                                             \
   develop(intx, ReplaySuppressInitializers, 2,                              \
           "Controls handling of class initialization during replay"         \
@@ -3237,8 +3244,8 @@
   develop(bool, ReplayIgnoreInitErrors, false,                              \
           "Ignore exceptions thrown during initialization for replay")      \
                                                                             \
-  develop(bool, DumpReplayDataOnError, true,                                \
-          "record replay data for crashing compiler threads")               \
+  product(bool, DumpReplayDataOnError, true,                                \
+          "Record replay data for crashing compiler threads")               \
                                                                             \
   product(bool, CICompilerCountPerCPU, false,                               \
           "1 compiler thread for log(N CPUs)")                              \
@@ -3247,7 +3254,9 @@
           "Fire OutOfMemoryErrors throughout CI for testing the compiler "  \
           "(non-negative value throws OOM after this many CI accesses "     \
           "in each compile)")                                               \
-                                                                            \
+  notproduct(intx, CICrashAt, -1,                                           \
+          "id of compilation to trigger assert in compiler thread for "     \
+          "the purpose of testing, e.g. generation of replay data")         \
   notproduct(bool, CIObjectFactoryVerify, false,                            \
           "enable potentially expensive verification in ciObjectFactory")   \
                                                                             \
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp	Thu May 16 11:47:51 2013 +0100
@@ -2404,7 +2404,7 @@
   size_t sz = strlen (SyncKnobs) ;
   char * knobs = (char *) malloc (sz + 2) ;
   if (knobs == NULL) {
-     vm_exit_out_of_memory (sz + 2, "Parse SyncKnobs") ;
+     vm_exit_out_of_memory (sz + 2, OOM_MALLOC_ERROR, "Parse SyncKnobs") ;
      guarantee (0, "invariant") ;
   }
   strcpy (knobs, SyncKnobs) ;
--- a/hotspot/src/share/vm/runtime/os.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/os.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1457,6 +1457,18 @@
 
   return result;
 }
+
+char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint,
+   MEMFLAGS flags) {
+  char* result = pd_reserve_memory(bytes, addr, alignment_hint);
+  if (result != NULL) {
+    MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC);
+    MemTracker::record_virtual_memory_type((address)result, flags);
+  }
+
+  return result;
+}
+
 char* os::attempt_reserve_memory_at(size_t bytes, char* addr) {
   char* result = pd_attempt_reserve_memory_at(bytes, addr);
   if (result != NULL) {
--- a/hotspot/src/share/vm/runtime/os.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/os.hpp	Thu May 16 11:47:51 2013 +0100
@@ -255,6 +255,8 @@
   static int    vm_allocation_granularity();
   static char*  reserve_memory(size_t bytes, char* addr = 0,
                                size_t alignment_hint = 0);
+  static char*  reserve_memory(size_t bytes, char* addr,
+                               size_t alignment_hint, MEMFLAGS flags);
   static char*  reserve_memory_aligned(size_t size, size_t alignment);
   static char*  attempt_reserve_memory_at(size_t bytes, char* addr);
   static void   split_reserved_memory(char *base, size_t size,
@@ -454,6 +456,7 @@
   // File i/o operations
   static const int default_file_open_flags();
   static int open(const char *path, int oflag, int mode);
+  static FILE* open(int fd, const char* mode);
   static int close(int fd);
   static jlong lseek(int fd, jlong offset, int whence);
   static char* native_path(char *path);
@@ -477,7 +480,7 @@
   static const char*    dll_file_extension();
 
   static const char*    get_temp_directory();
-  static const char*    get_current_directory(char *buf, int buflen);
+  static const char*    get_current_directory(char *buf, size_t buflen);
 
   // Builds a platform-specific full library path given a ld path and lib name
   // Returns true if buffer contains full path to existing file, false otherwise
--- a/hotspot/src/share/vm/runtime/serviceThread.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/serviceThread.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
 #include "runtime/mutexLocker.hpp"
 #include "prims/jvmtiImpl.hpp"
 #include "services/gcNotifier.hpp"
+#include "services/diagnosticArgument.hpp"
+#include "services/diagnosticFramework.hpp"
 
 ServiceThread* ServiceThread::_instance = NULL;
 
@@ -83,6 +85,7 @@
     bool sensors_changed = false;
     bool has_jvmti_events = false;
     bool has_gc_notification_event = false;
+    bool has_dcmd_notification_event = false;
     JvmtiDeferredEvent jvmti_event;
     {
       // Need state transition ThreadBlockInVM so that this thread
@@ -98,7 +101,8 @@
       MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
       while (!(sensors_changed = LowMemoryDetector::has_pending_requests()) &&
              !(has_jvmti_events = JvmtiDeferredEventQueue::has_events()) &&
-              !(has_gc_notification_event = GCNotifier::has_event())) {
+              !(has_gc_notification_event = GCNotifier::has_event()) &&
+              !(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification())) {
         // wait until one of the sensors has pending requests, or there is a
         // pending JVMTI event or JMX GC notification to post
         Service_lock->wait(Mutex::_no_safepoint_check_flag);
@@ -120,6 +124,10 @@
     if(has_gc_notification_event) {
         GCNotifier::sendNotification(CHECK);
     }
+
+    if(has_dcmd_notification_event) {
+      DCmdFactory::send_notification(CHECK);
+    }
   }
 }
 
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1316,12 +1316,6 @@
   assert(stub_frame.is_runtime_frame(), "sanity check");
   frame caller_frame = stub_frame.sender(&reg_map);
 
-  // MethodHandle invokes don't have a CompiledIC and should always
-  // simply redispatch to the callee_target.
-  address   sender_pc = caller_frame.pc();
-  CodeBlob* sender_cb = caller_frame.cb();
-  nmethod*  sender_nm = sender_cb->as_nmethod_or_null();
-
   if (caller_frame.is_interpreted_frame() ||
       caller_frame.is_entry_frame()) {
     Method* callee = thread->callee_target();
--- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.cpp	Thu May 16 11:47:51 2013 +0100
@@ -154,9 +154,10 @@
 // Set carry flags on the counters if necessary
 void SimpleThresholdPolicy::handle_counter_overflow(Method* method) {
   MethodCounters *mcs = method->method_counters();
-  assert(mcs != NULL, "");
-  set_carry_if_necessary(mcs->invocation_counter());
-  set_carry_if_necessary(mcs->backedge_counter());
+  if (mcs != NULL) {
+    set_carry_if_necessary(mcs->invocation_counter());
+    set_carry_if_necessary(mcs->backedge_counter());
+  }
   MethodData* mdo = method->method_data();
   if (mdo != NULL) {
     set_carry_if_necessary(mdo->invocation_counter());
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp	Thu May 16 11:47:51 2013 +0100
@@ -147,7 +147,7 @@
     TraceTime timer("StubRoutines generation 1", TraceStartupTime);
     _code1 = BufferBlob::create("StubRoutines (1)", code_size1);
     if (_code1 == NULL) {
-      vm_exit_out_of_memory(code_size1, "CodeCache: no room for StubRoutines (1)");
+      vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)");
     }
     CodeBuffer buffer(_code1);
     StubGenerator_generate(&buffer, false);
@@ -199,7 +199,7 @@
     TraceTime timer("StubRoutines generation 2", TraceStartupTime);
     _code2 = BufferBlob::create("StubRoutines (2)", code_size2);
     if (_code2 == NULL) {
-      vm_exit_out_of_memory(code_size2, "CodeCache: no room for StubRoutines (2)");
+      vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)");
     }
     CodeBuffer buffer(_code2);
     StubGenerator_generate(&buffer, true);
--- a/hotspot/src/share/vm/runtime/sweeper.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp	Thu May 16 11:47:51 2013 +0100
@@ -136,13 +136,12 @@
 
 jint      NMethodSweeper::_locked_seen = 0;
 jint      NMethodSweeper::_not_entrant_seen_on_stack = 0;
-bool      NMethodSweeper::_rescan = false;
-bool      NMethodSweeper::_do_sweep = false;
-bool      NMethodSweeper::_was_full = false;
-jint      NMethodSweeper::_advise_to_sweep = 0;
-jlong     NMethodSweeper::_last_was_full = 0;
-uint      NMethodSweeper::_highest_marked = 0;
-long      NMethodSweeper::_was_full_traversal = 0;
+bool      NMethodSweeper::_resweep = false;
+jint      NMethodSweeper::_flush_token = 0;
+jlong     NMethodSweeper::_last_full_flush_time = 0;
+int       NMethodSweeper::_highest_marked = 0;
+int       NMethodSweeper::_dead_compile_ids = 0;
+long      NMethodSweeper::_last_flush_traversal_id = 0;
 
 class MarkActivationClosure: public CodeBlobClosure {
 public:
@@ -155,20 +154,16 @@
 };
 static MarkActivationClosure mark_activation_closure;
 
+bool NMethodSweeper::sweep_in_progress() {
+  return (_current != NULL);
+}
+
 void NMethodSweeper::scan_stacks() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
   if (!MethodFlushing) return;
-  _do_sweep = true;
 
   // No need to synchronize access, since this is always executed at a
-  // safepoint.  If we aren't in the middle of scan and a rescan
-  // hasn't been requested then just return. If UseCodeCacheFlushing is on and
-  // code cache flushing is in progress, don't skip sweeping to help make progress
-  // clearing space in the code cache.
-  if ((_current == NULL && !_rescan) && !(UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs())) {
-    _do_sweep = false;
-    return;
-  }
+  // safepoint.
 
   // Make sure CompiledIC_lock in unlocked, since we might update some
   // inline caches. If it is, we just bail-out and try later.
@@ -176,7 +171,7 @@
 
   // Check for restart
   assert(CodeCache::find_blob_unsafe(_current) == _current, "Sweeper nmethod cached state invalid");
-  if (_current == NULL) {
+  if (!sweep_in_progress() && _resweep) {
     _seen        = 0;
     _invocations = NmethodSweepFraction;
     _current     = CodeCache::first_nmethod();
@@ -187,39 +182,30 @@
     Threads::nmethods_do(&mark_activation_closure);
 
     // reset the flags since we started a scan from the beginning.
-    _rescan = false;
+    _resweep = false;
     _locked_seen = 0;
     _not_entrant_seen_on_stack = 0;
   }
 
   if (UseCodeCacheFlushing) {
-    if (!CodeCache::needs_flushing()) {
-      // scan_stacks() runs during a safepoint, no race with setters
-      _advise_to_sweep = 0;
+    // only allow new flushes after the interval is complete.
+    jlong now           = os::javaTimeMillis();
+    jlong max_interval  = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
+    jlong curr_interval = now - _last_full_flush_time;
+    if (curr_interval > max_interval) {
+      _flush_token = 0;
     }
 
-    if (was_full()) {
-      // There was some progress so attempt to restart the compiler
-      jlong now           = os::javaTimeMillis();
-      jlong max_interval  = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
-      jlong curr_interval = now - _last_was_full;
-      if ((!CodeCache::needs_flushing()) && (curr_interval > max_interval)) {
-        CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
-        set_was_full(false);
-
-        // Update the _last_was_full time so we can tell how fast the
-        // code cache is filling up
-        _last_was_full = os::javaTimeMillis();
-
-        log_sweep("restart_compiler");
-      }
+    if (!CodeCache::needs_flushing() && !CompileBroker::should_compile_new_jobs()) {
+      CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
+      log_sweep("restart_compiler");
     }
   }
 }
 
 void NMethodSweeper::possibly_sweep() {
   assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode");
-  if ((!MethodFlushing) || (!_do_sweep)) return;
+  if (!MethodFlushing || !sweep_in_progress()) return;
 
   if (_invocations > 0) {
     // Only one thread at a time will sweep
@@ -253,6 +239,14 @@
     tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations);
   }
 
+  if (!CompileBroker::should_compile_new_jobs()) {
+    // If we have turned off compilations we might as well do full sweeps
+    // in order to reach the clean state faster. Otherwise the sleeping compiler
+    // threads will slow down sweeping. After a few iterations the cache
+    // will be clean and sweeping stops (_resweep will not be set)
+    _invocations = 1;
+  }
+
   // We want to visit all nmethods after NmethodSweepFraction
   // invocations so divide the remaining number of nmethods by the
   // remaining number of invocations.  This is only an estimate since
@@ -296,7 +290,7 @@
 
   assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache");
 
-  if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) {
+  if (!sweep_in_progress() && !_resweep && (_locked_seen || _not_entrant_seen_on_stack)) {
     // we've completed a scan without making progress but there were
     // nmethods we were unable to process either because they were
     // locked or were still on stack.  We don't have to aggresively
@@ -318,6 +312,13 @@
   if (_invocations == 1) {
     log_sweep("finished");
   }
+
+  // Sweeper is the only case where memory is released,
+  // check here if it is time to restart the compiler.
+  if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs() && !CodeCache::needs_flushing()) {
+    CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
+    log_sweep("restart_compiler");
+  }
 }
 
 class NMethodMarker: public StackObj {
@@ -392,7 +393,7 @@
         tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
       }
       nm->mark_for_reclamation();
-      _rescan = true;
+      _resweep = true;
       SWEEP(nm);
     }
   } else if (nm->is_not_entrant()) {
@@ -403,7 +404,7 @@
         tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
       }
       nm->make_zombie();
-      _rescan = true;
+      _resweep = true;
       SWEEP(nm);
     } else {
       // Still alive, clean up its inline caches
@@ -425,16 +426,15 @@
       release_nmethod(nm);
     } else {
       nm->make_zombie();
-      _rescan = true;
+      _resweep = true;
       SWEEP(nm);
     }
   } else {
     assert(nm->is_alive(), "should be alive");
 
     if (UseCodeCacheFlushing) {
-      if ((nm->method()->code() != nm) && !(nm->is_locked_by_vm()) && !(nm->is_osr_method()) &&
-          (_traversals > _was_full_traversal+2) && (((uint)nm->compile_id()) < _highest_marked) &&
-          CodeCache::needs_flushing()) {
+      if (nm->is_speculatively_disconnected() && !nm->is_locked_by_vm() && !nm->is_osr_method() &&
+          (_traversals > _last_flush_traversal_id + 2) && (nm->compile_id() < _highest_marked)) {
         // This method has not been called since the forced cleanup happened
         nm->make_not_entrant();
       }
@@ -457,41 +457,27 @@
 // _code field is restored and the Method*/nmethod
 // go back to their normal state.
 void NMethodSweeper::handle_full_code_cache(bool is_full) {
-  // Only the first one to notice can advise us to start early cleaning
-  if (!is_full){
-    jint old = Atomic::cmpxchg( 1, &_advise_to_sweep, 0 );
-    if (old != 0) {
-      return;
-    }
-  }
 
   if (is_full) {
     // Since code cache is full, immediately stop new compiles
-    bool did_set = CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
-    if (!did_set) {
-      // only the first to notice can start the cleaning,
-      // others will go back and block
-      return;
+    if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) {
+      log_sweep("disable_compiler");
     }
-    set_was_full(true);
+  }
 
-    // If we run out within MinCodeCacheFlushingInterval of the last unload time, give up
-    jlong now = os::javaTimeMillis();
-    jlong max_interval = (jlong)MinCodeCacheFlushingInterval * (jlong)1000;
-    jlong curr_interval = now - _last_was_full;
-    if (curr_interval < max_interval) {
-      _rescan = true;
-      log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'",
-                           curr_interval/1000);
-      return;
-    }
+  // Make sure only one thread can flush
+  // The token is reset after CodeCacheMinimumFlushInterval in scan stacks,
+  // no need to check the timeout here.
+  jint old = Atomic::cmpxchg( 1, &_flush_token, 0 );
+  if (old != 0) {
+    return;
   }
 
   VM_HandleFullCodeCache op(is_full);
   VMThread::execute(&op);
 
-  // rescan again as soon as possible
-  _rescan = true;
+  // resweep again as soon as possible
+  _resweep = true;
 }
 
 void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
@@ -500,62 +486,64 @@
 
   debug_only(jlong start = os::javaTimeMillis();)
 
-  if ((!was_full()) && (is_full)) {
-    if (!CodeCache::needs_flushing()) {
-      log_sweep("restart_compiler");
-      CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
-      return;
-    }
-  }
+  // Traverse the code cache trying to dump the oldest nmethods
+  int curr_max_comp_id = CompileBroker::get_compilation_id();
+  int flush_target = ((curr_max_comp_id - _dead_compile_ids) / CodeCacheFlushingFraction) + _dead_compile_ids;
 
-  // Traverse the code cache trying to dump the oldest nmethods
-  uint curr_max_comp_id = CompileBroker::get_compilation_id();
-  uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked;
   log_sweep("start_cleaning");
 
   nmethod* nm = CodeCache::alive_nmethod(CodeCache::first());
   jint disconnected = 0;
   jint made_not_entrant  = 0;
+  jint nmethod_count = 0;
+
   while ((nm != NULL)){
-    uint curr_comp_id = nm->compile_id();
+    int curr_comp_id = nm->compile_id();
 
     // OSR methods cannot be flushed like this. Also, don't flush native methods
     // since they are part of the JDK in most cases
-    if (nm->is_in_use() && (!nm->is_osr_method()) && (!nm->is_locked_by_vm()) &&
-        (!nm->is_native_method()) && ((curr_comp_id < flush_target))) {
+    if (!nm->is_osr_method() && !nm->is_locked_by_vm() && !nm->is_native_method()) {
+
+      // only count methods that can be speculatively disconnected
+      nmethod_count++;
 
-      if ((nm->method()->code() == nm)) {
-        // This method has not been previously considered for
-        // unloading or it was restored already
-        CodeCache::speculatively_disconnect(nm);
-        disconnected++;
-      } else if (nm->is_speculatively_disconnected()) {
-        // This method was previously considered for preemptive unloading and was not called since then
-        CompilationPolicy::policy()->delay_compilation(nm->method());
-        nm->make_not_entrant();
-        made_not_entrant++;
-      }
+      if (nm->is_in_use() && (curr_comp_id < flush_target)) {
+        if ((nm->method()->code() == nm)) {
+          // This method has not been previously considered for
+          // unloading or it was restored already
+          CodeCache::speculatively_disconnect(nm);
+          disconnected++;
+        } else if (nm->is_speculatively_disconnected()) {
+          // This method was previously considered for preemptive unloading and was not called since then
+          CompilationPolicy::policy()->delay_compilation(nm->method());
+          nm->make_not_entrant();
+          made_not_entrant++;
+        }
 
-      if (curr_comp_id > _highest_marked) {
-        _highest_marked = curr_comp_id;
+        if (curr_comp_id > _highest_marked) {
+          _highest_marked = curr_comp_id;
+        }
       }
     }
     nm = CodeCache::alive_nmethod(CodeCache::next(nm));
   }
 
+  // remember how many compile_ids wheren't seen last flush.
+  _dead_compile_ids = curr_max_comp_id - nmethod_count;
+
   log_sweep("stop_cleaning",
                        "disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'",
                        disconnected, made_not_entrant);
 
   // Shut off compiler. Sweeper will start over with a new stack scan and
   // traversal cycle and turn it back on if it clears enough space.
-  if (was_full()) {
-    _last_was_full = os::javaTimeMillis();
-    CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation);
+  if (is_full) {
+    _last_full_flush_time = os::javaTimeMillis();
   }
 
   // After two more traversals the sweeper will get rid of unrestored nmethods
-  _was_full_traversal = _traversals;
+  _last_flush_traversal_id = _traversals;
+  _resweep = true;
 #ifdef ASSERT
   jlong end = os::javaTimeMillis();
   if(PrintMethodFlushing && Verbose) {
--- a/hotspot/src/share/vm/runtime/sweeper.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/sweeper.hpp	Thu May 16 11:47:51 2013 +0100
@@ -35,26 +35,29 @@
   static nmethod*  _current;      // Current nmethod
   static int       _seen;         // Nof. nmethod we have currently processed in current pass of CodeCache
 
-  static volatile int      _invocations;   // No. of invocations left until we are completed with this pass
-  static volatile int      _sweep_started; // Flag to control conc sweeper
+  static volatile int  _invocations;   // No. of invocations left until we are completed with this pass
+  static volatile int  _sweep_started; // Flag to control conc sweeper
 
-  static bool      _rescan;          // Indicates that we should do a full rescan of the
-                                     // of the code cache looking for work to do.
-  static bool      _do_sweep;        // Flag to skip the conc sweep if no stack scan happened
-  static int       _locked_seen;     // Number of locked nmethods encountered during the scan
+  //The following are reset in scan_stacks and synchronized by the safepoint
+  static bool      _resweep;           // Indicates that a change has happend and we want another sweep,
+                                       // always checked and reset at a safepoint so memory will be in sync.
+  static int       _locked_seen;       // Number of locked nmethods encountered during the scan
   static int       _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack
+  static jint      _flush_token;       // token that guards method flushing, making sure it is executed only once.
 
-  static bool      _was_full;        // remember if we did emergency unloading
-  static jint      _advise_to_sweep; // flag to indicate code cache getting full
-  static jlong     _last_was_full;   // timestamp of last emergency unloading
-  static uint      _highest_marked;   // highest compile id dumped at last emergency unloading
-  static long      _was_full_traversal;   // trav number at last emergency unloading
+  // These are set during a flush, a VM-operation
+  static long      _last_flush_traversal_id; // trav number at last flush unloading
+  static jlong     _last_full_flush_time;    // timestamp of last emergency unloading
+
+  // These are synchronized by the _sweep_started token
+  static int       _highest_marked;   // highest compile id dumped at last emergency unloading
+  static int       _dead_compile_ids; // number of compile ids that where not in the cache last flush
 
   static void process_nmethod(nmethod *nm);
-
   static void release_nmethod(nmethod* nm);
 
   static void log_sweep(const char* msg, const char* format = NULL, ...);
+  static bool sweep_in_progress();
 
  public:
   static long traversal_count() { return _traversals; }
@@ -71,17 +74,14 @@
   static void possibly_sweep();   // Compiler threads call this to sweep
 
   static void notify(nmethod* nm) {
-    // Perform a full scan of the code cache from the beginning.  No
+    // Request a new sweep of the code cache from the beginning. No
     // need to synchronize the setting of this flag since it only
     // changes to false at safepoint so we can never overwrite it with false.
-     _rescan = true;
+     _resweep = true;
   }
 
   static void handle_full_code_cache(bool is_full); // Called by compilers who fail to allocate
   static void speculative_disconnect_nmethods(bool was_full);   // Called by vm op to deal with alloc failure
-
-  static void set_was_full(bool state) { _was_full = state; }
-  static bool was_full() { return _was_full; }
 };
 
 #endif // SHARE_VM_RUNTIME_SWEEPER_HPP
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1018,7 +1018,8 @@
         // We might be able to induce a STW safepoint and scavenge enough
         // objectMonitors to permit progress.
         if (temp == NULL) {
-            vm_exit_out_of_memory (sizeof (ObjectMonitor[_BLOCKSIZE]), "Allocate ObjectMonitors") ;
+            vm_exit_out_of_memory (sizeof (ObjectMonitor[_BLOCKSIZE]), OOM_MALLOC_ERROR,
+                                   "Allocate ObjectMonitors");
         }
 
         // Format the block.
--- a/hotspot/src/share/vm/runtime/thread.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Thu May 16 11:47:51 2013 +0100
@@ -3447,7 +3447,8 @@
 
   assert (Universe::is_fully_initialized(), "not initialized");
   if (VerifyDuringStartup) {
-    VM_Verify verify_op(false /* silent */);   // make sure we're starting with a clean slate
+    // Make sure we're starting with a clean slate.
+    VM_Verify verify_op;
     VMThread::execute(&verify_op);
   }
 
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/virtualspace.cpp	Thu May 16 11:47:51 2013 +0100
@@ -60,72 +60,6 @@
   initialize(size, alignment, large, NULL, 0, executable);
 }
 
-char *
-ReservedSpace::align_reserved_region(char* addr, const size_t len,
-                                     const size_t prefix_size,
-                                     const size_t prefix_align,
-                                     const size_t suffix_size,
-                                     const size_t suffix_align)
-{
-  assert(addr != NULL, "sanity");
-  const size_t required_size = prefix_size + suffix_size;
-  assert(len >= required_size, "len too small");
-
-  const size_t s = size_t(addr);
-  const size_t beg_ofs = (s + prefix_size) & (suffix_align - 1);
-  const size_t beg_delta = beg_ofs == 0 ? 0 : suffix_align - beg_ofs;
-
-  if (len < beg_delta + required_size) {
-     return NULL; // Cannot do proper alignment.
-  }
-  const size_t end_delta = len - (beg_delta + required_size);
-
-  if (beg_delta != 0) {
-    os::release_memory(addr, beg_delta);
-  }
-
-  if (end_delta != 0) {
-    char* release_addr = (char*) (s + beg_delta + required_size);
-    os::release_memory(release_addr, end_delta);
-  }
-
-  return (char*) (s + beg_delta);
-}
-
-char* ReservedSpace::reserve_and_align(const size_t reserve_size,
-                                       const size_t prefix_size,
-                                       const size_t prefix_align,
-                                       const size_t suffix_size,
-                                       const size_t suffix_align)
-{
-  assert(reserve_size > prefix_size + suffix_size, "should not be here");
-
-  char* raw_addr = os::reserve_memory(reserve_size, NULL, prefix_align);
-  if (raw_addr == NULL) return NULL;
-
-  char* result = align_reserved_region(raw_addr, reserve_size, prefix_size,
-                                       prefix_align, suffix_size,
-                                       suffix_align);
-  if (result == NULL && !os::release_memory(raw_addr, reserve_size)) {
-    fatal("os::release_memory failed");
-  }
-
-#ifdef ASSERT
-  if (result != NULL) {
-    const size_t raw = size_t(raw_addr);
-    const size_t res = size_t(result);
-    assert(res >= raw, "alignment decreased start addr");
-    assert(res + prefix_size + suffix_size <= raw + reserve_size,
-           "alignment increased end addr");
-    assert((res & (prefix_align - 1)) == 0, "bad alignment of prefix");
-    assert(((res + prefix_size) & (suffix_align - 1)) == 0,
-           "bad alignment of suffix");
-  }
-#endif
-
-  return result;
-}
-
 // Helper method.
 static bool failed_to_reserve_as_requested(char* base, char* requested_address,
                                            const size_t size, bool special)
@@ -155,92 +89,6 @@
   return true;
 }
 
-ReservedSpace::ReservedSpace(const size_t suffix_size,
-                             const size_t suffix_align,
-                             char* requested_address,
-                             const size_t noaccess_prefix)
-{
-  assert(suffix_size != 0, "sanity");
-  assert(suffix_align != 0, "sanity");
-  assert((suffix_size & (suffix_align - 1)) == 0,
-    "suffix_size not divisible by suffix_align");
-
-  // Assert that if noaccess_prefix is used, it is the same as prefix_align.
-  // Add in noaccess_prefix to prefix
-  const size_t adjusted_prefix_size = noaccess_prefix;
-  const size_t size = adjusted_prefix_size + suffix_size;
-
-  // On systems where the entire region has to be reserved and committed up
-  // front, the compound alignment normally done by this method is unnecessary.
-  const bool try_reserve_special = UseLargePages &&
-    suffix_align == os::large_page_size();
-  if (!os::can_commit_large_page_memory() && try_reserve_special) {
-    initialize(size, suffix_align, true, requested_address, noaccess_prefix,
-               false);
-    return;
-  }
-
-  _base = NULL;
-  _size = 0;
-  _alignment = 0;
-  _special = false;
-  _noaccess_prefix = 0;
-  _executable = false;
-
-  // Optimistically try to reserve the exact size needed.
-  char* addr;
-  if (requested_address != 0) {
-    requested_address -= noaccess_prefix; // adjust address
-    assert(requested_address != NULL, "huge noaccess prefix?");
-    addr = os::attempt_reserve_memory_at(size, requested_address);
-    if (failed_to_reserve_as_requested(addr, requested_address, size, false)) {
-      // OS ignored requested address. Try different address.
-      addr = NULL;
-    }
-  } else {
-    addr = os::reserve_memory(size, NULL, suffix_align);
-  }
-  if (addr == NULL) return;
-
-  // Check whether the result has the needed alignment
-  const size_t ofs = (size_t(addr) + adjusted_prefix_size) & (suffix_align - 1);
-  if (ofs != 0) {
-    // Wrong alignment.  Release, allocate more space and do manual alignment.
-    //
-    // On most operating systems, another allocation with a somewhat larger size
-    // will return an address "close to" that of the previous allocation.  The
-    // result is often the same address (if the kernel hands out virtual
-    // addresses from low to high), or an address that is offset by the increase
-    // in size.  Exploit that to minimize the amount of extra space requested.
-    if (!os::release_memory(addr, size)) {
-      fatal("os::release_memory failed");
-    }
-
-    const size_t extra = MAX2(ofs, suffix_align - ofs);
-    addr = reserve_and_align(size + extra, adjusted_prefix_size, suffix_align,
-                             suffix_size, suffix_align);
-    if (addr == NULL) {
-      // Try an even larger region.  If this fails, address space is exhausted.
-      addr = reserve_and_align(size + suffix_align, adjusted_prefix_size,
-                               suffix_align, suffix_size, suffix_align);
-    }
-
-    if (requested_address != 0 &&
-        failed_to_reserve_as_requested(addr, requested_address, size, false)) {
-      // As a result of the alignment constraints, the allocated addr differs
-      // from the requested address. Return back to the caller who can
-      // take remedial action (like try again without a requested address).
-      assert(_base == NULL, "should be");
-      return;
-    }
-  }
-
-  _base = addr;
-  _size = size;
-  _alignment = suffix_align;
-  _noaccess_prefix = noaccess_prefix;
-}
-
 void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
                                char* requested_address,
                                const size_t noaccess_prefix,
@@ -476,20 +324,6 @@
   protect_noaccess_prefix(size);
 }
 
-ReservedHeapSpace::ReservedHeapSpace(const size_t heap_space_size,
-                                     const size_t alignment,
-                                     char* requested_address) :
-  ReservedSpace(heap_space_size, alignment,
-                requested_address,
-                (UseCompressedOops && (Universe::narrow_oop_base() != NULL) &&
-                 Universe::narrow_oop_use_implicit_null_checks()) ?
-                  lcm(os::vm_page_size(), alignment) : 0) {
-  if (base() > 0) {
-    MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap);
-  }
-  protect_noaccess_prefix(heap_space_size);
-}
-
 // Reserve space for code segment.  Same as Java heap only we mark this as
 // executable.
 ReservedCodeSpace::ReservedCodeSpace(size_t r_size,
--- a/hotspot/src/share/vm/runtime/virtualspace.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/virtualspace.hpp	Thu May 16 11:47:51 2013 +0100
@@ -47,28 +47,6 @@
                   const size_t noaccess_prefix,
                   bool executable);
 
-  // Release parts of an already-reserved memory region [addr, addr + len) to
-  // get a new region that has "compound alignment."  Return the start of the
-  // resulting region, or NULL on failure.
-  //
-  // The region is logically divided into a prefix and a suffix.  The prefix
-  // starts at the result address, which is aligned to prefix_align.  The suffix
-  // starts at result address + prefix_size, which is aligned to suffix_align.
-  // The total size of the result region is size prefix_size + suffix_size.
-  char* align_reserved_region(char* addr, const size_t len,
-                              const size_t prefix_size,
-                              const size_t prefix_align,
-                              const size_t suffix_size,
-                              const size_t suffix_align);
-
-  // Reserve memory, call align_reserved_region() to alignment it and return the
-  // result.
-  char* reserve_and_align(const size_t reserve_size,
-                          const size_t prefix_size,
-                          const size_t prefix_align,
-                          const size_t suffix_size,
-                          const size_t suffix_align);
-
  protected:
   // Create protection page at the beginning of the space.
   void protect_noaccess_prefix(const size_t size);
@@ -79,9 +57,6 @@
   ReservedSpace(size_t size, size_t alignment, bool large,
                 char* requested_address = NULL,
                 const size_t noaccess_prefix = 0);
-  ReservedSpace(const size_t suffix_size, const size_t suffix_align,
-                char* requested_address,
-                const size_t noaccess_prefix = 0);
   ReservedSpace(size_t size, size_t alignment, bool large, bool executable);
 
   // Accessors
@@ -128,8 +103,6 @@
   // Constructor
   ReservedHeapSpace(size_t size, size_t forced_base_alignment,
                     bool large, char* requested_address);
-  ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align,
-                    char* requested_address);
 };
 
 // Class encapsulating behavior specific memory space for Code
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Thu May 16 11:47:51 2013 +0100
@@ -828,6 +828,7 @@
   nonstatic_field(nmethod,             _lock_count,                                   jint)                                  \
   nonstatic_field(nmethod,             _stack_traversal_mark,                         long)                                  \
   nonstatic_field(nmethod,             _compile_id,                                   int)                                   \
+  nonstatic_field(nmethod,             _comp_level,                                   int)                                   \
   nonstatic_field(nmethod,             _exception_cache,                              ExceptionCache*)                       \
   nonstatic_field(nmethod,             _marked_for_deoptimization,                    bool)                                  \
                                                                                                                              \
--- a/hotspot/src/share/vm/runtime/vmThread.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp	Thu May 16 11:47:51 2013 +0100
@@ -293,7 +293,7 @@
     os::check_heap();
     // Silent verification so as not to pollute normal output,
     // unless we really asked for it.
-    Universe::verify(!(PrintGCDetails || Verbose));
+    Universe::verify(!(PrintGCDetails || Verbose) || VerifySilently);
   }
 
   CompileBroker::set_should_block();
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp	Thu May 16 11:47:51 2013 +0100
@@ -302,7 +302,7 @@
  private:
   bool _silent;
  public:
-  VM_Verify(bool silent) : _silent(silent) {}
+  VM_Verify(bool silent = VerifySilently) : _silent(silent) {}
   VMOp_Type type() const { return VMOp_Verify; }
   void doit();
 };
--- a/hotspot/src/share/vm/services/attachListener.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/attachListener.cpp	Thu May 16 11:47:51 2013 +0100
@@ -157,7 +157,7 @@
   Thread* THREAD = Thread::current();
   // All the supplied jcmd arguments are stored as a single
   // string (op->arg(0)). This is parsed by the Dcmd framework.
-  DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD);
+  DCmd::parse_and_execute(DCmd_Source_AttachAPI, out, op->arg(0), ' ', THREAD);
   if (HAS_PENDING_EXCEPTION) {
     java_lang_Throwable::print(PENDING_EXCEPTION, out);
     out->cr();
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp	Thu May 16 11:47:51 2013 +0100
@@ -34,26 +34,33 @@
 
 void DCmdRegistrant::register_dcmds(){
   // Registration of the diagnostic commands
-  // First boolean argument specifies if the command is enabled
-  // Second boolean argument specifies if the command is hidden
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(true, false));
+  // First argument specifies which interfaces will export the command
+  // Second argument specifies if the command is enabled
+  // Third  argument specifies if the command is hidden
+  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
+                         | DCmd_Source_MBean;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
 #if INCLUDE_SERVICES // Heap dumping/inspection supported
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(true, false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
 #endif // INCLUDE_SERVICES
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(true, false));
-  //Enhanced JMX Agent Support
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(true,false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(true,false));
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
+
+  // Enhanced JMX Agent Support
+  // These commands won't be exported via the DiagnosticCommandMBean until an
+  // appropriate permission is created for them
+  uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
 
 }
 
@@ -72,29 +79,37 @@
   _dcmdparser.add_dcmd_argument(&_cmd);
 };
 
-void HelpDCmd::execute(TRAPS) {
+void HelpDCmd::execute(DCmdSource source, TRAPS) {
   if (_all.value()) {
-    GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list();
+    GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
     for (int i = 0; i < cmd_list->length(); i++) {
-      DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i),
+      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                   strlen(cmd_list->at(i)));
-      if (!factory->is_hidden()) {
-        output()->print_cr("%s%s", factory->name(),
-                           factory->is_enabled() ? "" : " [disabled]");
-        output()->print_cr("\t%s", factory->description());
-        output()->cr();
-      }
+      output()->print_cr("%s%s", factory->name(),
+                         factory->is_enabled() ? "" : " [disabled]");
+      output()->print_cr("\t%s", factory->description());
+      output()->cr();
       factory = factory->next();
     }
   } else if (_cmd.has_value()) {
     DCmd* cmd = NULL;
-    DCmdFactory* factory = DCmdFactory::factory(_cmd.value(),
+    DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
                                                 strlen(_cmd.value()));
     if (factory != NULL) {
       output()->print_cr("%s%s", factory->name(),
                          factory->is_enabled() ? "" : " [disabled]");
       output()->print_cr(factory->description());
       output()->print_cr("\nImpact: %s", factory->impact());
+      JavaPermission p = factory->permission();
+      if(p._class != NULL) {
+        if(p._action != NULL) {
+          output()->print_cr("\nPermission: %s(%s, %s)",
+                  p._class, p._name == NULL ? "null" : p._name, p._action);
+        } else {
+          output()->print_cr("\nPermission: %s(%s)",
+                  p._class, p._name == NULL ? "null" : p._name);
+        }
+      }
       output()->cr();
       cmd = factory->create_resource_instance(output());
       if (cmd != NULL) {
@@ -106,14 +121,12 @@
     }
   } else {
     output()->print_cr("The following commands are available:");
-    GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list();
+    GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
     for (int i = 0; i < cmd_list->length(); i++) {
-      DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i),
+      DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
                                                   strlen(cmd_list->at(i)));
-      if (!factory->is_hidden()) {
-        output()->print_cr("%s%s", factory->name(),
-                           factory->is_enabled() ? "" : " [disabled]");
-      }
+      output()->print_cr("%s%s", factory->name(),
+                         factory->is_enabled() ? "" : " [disabled]");
       factory = factory->_next;
     }
     output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
@@ -131,7 +144,7 @@
   }
 }
 
-void VersionDCmd::execute(TRAPS) {
+void VersionDCmd::execute(DCmdSource source, TRAPS) {
   output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(),
           Abstract_VM_Version::vm_release());
   JDK_Version jdk_version = JDK_Version::current();
@@ -150,7 +163,7 @@
   _dcmdparser.add_dcmd_option(&_all);
 }
 
-void PrintVMFlagsDCmd::execute(TRAPS) {
+void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
   if (_all.value()) {
     CommandLineFlags::printFlags(output(), true);
   } else {
@@ -169,7 +182,7 @@
     }
 }
 
-void PrintSystemPropertiesDCmd::execute(TRAPS) {
+void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
   // load sun.misc.VMSupport
   Symbol* klass = vmSymbols::sun_misc_VMSupport();
   Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
@@ -219,7 +232,7 @@
   _dcmdparser.add_dcmd_option(&_date);
 }
 
-void VMUptimeDCmd::execute(TRAPS) {
+void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
   if (_date.value()) {
     output()->date_stamp(true, "", ": ");
   }
@@ -239,11 +252,15 @@
   }
 }
 
-void SystemGCDCmd::execute(TRAPS) {
-  Universe::heap()->collect(GCCause::_java_lang_system_gc);
+void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
+  if (!DisableExplicitGC) {
+    Universe::heap()->collect(GCCause::_java_lang_system_gc);
+  } else {
+    output()->print_cr("Explicit GC is disabled, no GC has been performed.");
+  }
 }
 
-void RunFinalizationDCmd::execute(TRAPS) {
+void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
   Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(),
                                                  true, CHECK);
   instanceKlassHandle klass(THREAD, k);
@@ -263,7 +280,7 @@
   _dcmdparser.add_dcmd_argument(&_filename);
 }
 
-void HeapDumpDCmd::execute(TRAPS) {
+void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
   // Request a full GC before heap dump if _all is false
   // This helps reduces the amount of unreachable objects in the dump
   // and makes it easier to browse.
@@ -301,7 +318,7 @@
   _dcmdparser.add_dcmd_option(&_all);
 }
 
-void ClassHistogramDCmd::execute(TRAPS) {
+void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
   VM_GC_HeapInspection heapop(output(),
                               !_all.value() /* request full gc if false */,
                               true /* need_prologue */);
@@ -337,7 +354,7 @@
   _dcmdparser.add_dcmd_argument(&_columns);
 }
 
-void ClassStatsDCmd::execute(TRAPS) {
+void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
   if (!UnlockDiagnosticVMOptions) {
     output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions");
     return;
@@ -384,7 +401,7 @@
   _dcmdparser.add_dcmd_option(&_locks);
 }
 
-void ThreadDumpDCmd::execute(TRAPS) {
+void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
   // thread stacks
   VM_PrintThreads op1(output(), _locks.value());
   VMThread::execute(&op1);
@@ -526,7 +543,8 @@
   }
 }
 
-void JMXStartRemoteDCmd::execute(TRAPS) {
+
+void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
@@ -593,7 +611,7 @@
   // do nothing
 }
 
-void JMXStartLocalDCmd::execute(TRAPS) {
+void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
@@ -611,7 +629,7 @@
 }
 
 
-void JMXStopRemoteDCmd::execute(TRAPS) {
+void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
     ResourceMark rm(THREAD);
     HandleMark hm(THREAD);
 
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp	Thu May 16 11:47:51 2013 +0100
@@ -51,7 +51,7 @@
   }
   static const char* impact() { return "Low"; }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class VersionDCmd : public DCmd {
@@ -62,8 +62,13 @@
     return "Print JVM version information.";
   }
   static const char* impact() { return "Low"; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.util.PropertyPermission",
+                        "java.vm.version", "read"};
+    return p;
+  }
   static int num_arguments() { return 0; }
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class CommandLineDCmd : public DCmd {
@@ -74,8 +79,13 @@
     return "Print the command line used to start this VM instance.";
   }
   static const char* impact() { return "Low"; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments() { return 0; }
-  virtual void execute(TRAPS) {
+  virtual void execute(DCmdSource source, TRAPS) {
     Arguments::print_on(_output);
   }
 };
@@ -91,8 +101,13 @@
     static const char* impact() {
       return "Low";
     }
+    static const JavaPermission permission() {
+      JavaPermission p = {"java.util.PropertyPermission",
+                          "*", "read"};
+      return p;
+    }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 // See also: print_flag in attachListener.cpp
@@ -108,8 +123,13 @@
   static const char* impact() {
     return "Low";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class VMUptimeDCmd : public DCmdWithParser {
@@ -125,7 +145,7 @@
     return "Low";
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class SystemGCDCmd : public DCmd {
@@ -139,7 +159,7 @@
       return "Medium: Depends on Java heap size and content.";
     }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 class RunFinalizationDCmd : public DCmd {
@@ -153,7 +173,7 @@
       return "Medium: Depends on Java content.";
     }
     static int num_arguments() { return 0; }
-    virtual void execute(TRAPS);
+    virtual void execute(DCmdSource source, TRAPS);
 };
 
 #if INCLUDE_SERVICES   // Heap dumping supported
@@ -174,8 +194,13 @@
     return "High: Depends on Java heap size and content. "
            "Request a full GC unless the '-all' option is specified.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 #endif // INCLUDE_SERVICES
 
@@ -194,8 +219,13 @@
   static const char* impact() {
     return "High: Depends on Java heap size and content.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 class ClassStatsDCmd : public DCmdWithParser {
@@ -216,7 +246,7 @@
     return "High: Depends on Java heap size and content.";
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 // See also: thread_dump in attachListener.cpp
@@ -232,8 +262,13 @@
   static const char* impact() {
     return "Medium: Depends on the number of threads.";
   }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
+  }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 // Enhanced JMX Agent support
@@ -281,7 +316,7 @@
 
   static int num_arguments();
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 
 };
 
@@ -302,7 +337,7 @@
     return "Start local management agent.";
   }
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 
 };
 
@@ -321,7 +356,7 @@
     return "Stop remote management agent.";
   }
 
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
--- a/hotspot/src/share/vm/services/diagnosticFramework.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/diagnosticFramework.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -359,7 +359,7 @@
   while (arg != NULL) {
     array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                   arg->type(), arg->default_string(), arg->is_mandatory(),
-                  false, idx));
+                  false, arg->allow_multiple(), idx));
     idx++;
     arg = arg->next();
   }
@@ -367,32 +367,42 @@
   while (arg != NULL) {
     array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
                   arg->type(), arg->default_string(), arg->is_mandatory(),
-                  true));
+                  true, arg->allow_multiple()));
     arg = arg->next();
   }
   return array;
 }
 
 DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;
+bool DCmdFactory::_has_pending_jmx_notification = false;
 
-void DCmd::parse_and_execute(outputStream* out, const char* cmdline,
-                             char delim, TRAPS) {
+void DCmd::parse_and_execute(DCmdSource source, outputStream* out,
+                             const char* cmdline, char delim, TRAPS) {
 
   if (cmdline == NULL) return; // Nothing to do!
   DCmdIter iter(cmdline, '\n');
 
+  int count = 0;
   while (iter.has_next()) {
+    if(source == DCmd_Source_MBean && count > 0) {
+      // When diagnostic commands are invoked via JMX, each command line
+      // must contains one and only one command because of the Permission
+      // checks performed by the DiagnosticCommandMBean
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "Invalid syntax");
+    }
     CmdLine line = iter.next();
     if (line.is_stop()) {
       break;
     }
     if (line.is_executable()) {
-      DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK);
+      DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);
       assert(command != NULL, "command error must be handled before this line");
       DCmdMark mark(command);
       command->parse(&line, delim, CHECK);
-      command->execute(CHECK);
+      command->execute(source, CHECK);
     }
+    count++;
   }
 }
 
@@ -420,15 +430,78 @@
   return _dcmdparser.argument_info_array();
 }
 
-Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
+void DCmdFactory::push_jmx_notification_request() {
+  MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
+  _has_pending_jmx_notification = true;
+  Service_lock->notify_all();
+}
+
+void DCmdFactory::send_notification(TRAPS) {
+  DCmdFactory::send_notification_internal(THREAD);
+  // Clearing pending exception to avoid premature termination of
+  // the service thread
+  if (HAS_PENDING_EXCEPTION) {
+    CLEAR_PENDING_EXCEPTION;
+  }
+}
+void DCmdFactory::send_notification_internal(TRAPS) {
+  ResourceMark rm(THREAD);
+  HandleMark hm(THREAD);
+  bool notif = false;
+  {
+    MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
+    notif = _has_pending_jmx_notification;
+    _has_pending_jmx_notification = false;
+  }
+  if (notif) {
+
+    Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK);
+    instanceKlassHandle mgmt_factory_helper_klass(THREAD, k);
 
-DCmdFactory* DCmdFactory::factory(const char* name, size_t len) {
+    JavaValue result(T_OBJECT);
+    JavaCalls::call_static(&result,
+            mgmt_factory_helper_klass,
+            vmSymbols::getDiagnosticCommandMBean_name(),
+            vmSymbols::getDiagnosticCommandMBean_signature(),
+            CHECK);
+
+    instanceOop m = (instanceOop) result.get_jobject();
+    instanceHandle dcmd_mbean_h(THREAD, m);
+
+    Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK);
+    instanceKlassHandle dcmd_mbean_klass(THREAD, k2);
+
+    if (!dcmd_mbean_h->is_a(k2)) {
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+              "ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");
+    }
+
+    JavaValue result2(T_VOID);
+    JavaCallArguments args2(dcmd_mbean_h);
+
+    JavaCalls::call_virtual(&result2,
+            dcmd_mbean_klass,
+            vmSymbols::createDiagnosticFrameworkNotification_name(),
+            vmSymbols::void_method_signature(),
+            &args2,
+            CHECK);
+  }
+}
+
+Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
+bool DCmdFactory::_send_jmx_notification = false;
+
+DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
     if (strlen(factory->name()) == len &&
         strncmp(name, factory->name(), len) == 0) {
-      return factory;
+      if(factory->export_flags() & source) {
+        return factory;
+      } else {
+        return NULL;
+      }
     }
     factory = factory->_next;
   }
@@ -439,11 +512,16 @@
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   factory->_next = _DCmdFactoryList;
   _DCmdFactoryList = factory;
+  if (_send_jmx_notification && !factory->_hidden
+      && (factory->_export_flags & DCmd_Source_MBean)) {
+    DCmdFactory::push_jmx_notification_request();
+  }
   return 0; // Actually, there's no checks for duplicates
 }
 
-DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) {
-  DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len());
+DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line,
+                                      outputStream* out, TRAPS) {
+  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
   if (f != NULL) {
     if (f->is_enabled()) {
       THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
@@ -455,8 +533,9 @@
              "Unknown diagnostic command");
 }
 
-DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) {
-  DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len());
+DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,
+                                     outputStream* out, TRAPS) {
+  DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
   if (f != NULL) {
     if (!f->is_enabled()) {
       THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
@@ -468,12 +547,12 @@
              "Unknown diagnostic command");
 }
 
-GrowableArray<const char*>* DCmdFactory::DCmd_list() {
+GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   GrowableArray<const char*>* array = new GrowableArray<const char*>();
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
-    if (!factory->is_hidden()) {
+    if (!factory->is_hidden() && (factory->export_flags() & source)) {
       array->append(factory->name());
     }
     factory = factory->next();
@@ -481,15 +560,16 @@
   return array;
 }
 
-GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() {
+GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {
   MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
   GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();
   DCmdFactory* factory = _DCmdFactoryList;
   while (factory != NULL) {
-    if (!factory->is_hidden()) {
+    if (!factory->is_hidden() && (factory->export_flags() & source)) {
       array->append(new DCmdInfo(factory->name(),
                     factory->description(), factory->impact(),
-                    factory->num_arguments(), factory->is_enabled()));
+                    factory->permission(), factory->num_arguments(),
+                    factory->is_enabled()));
     }
     factory = factory->next();
   }
--- a/hotspot/src/share/vm/services/diagnosticFramework.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/diagnosticFramework.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,22 @@
 #include "utilities/ostream.hpp"
 
 
+enum DCmdSource {
+  DCmd_Source_Internal  = 0x01U,  // invocation from the JVM
+  DCmd_Source_AttachAPI = 0x02U,  // invocation via the attachAPI
+  DCmd_Source_MBean     = 0x04U   // invocation via a MBean
+};
+
+// Warning: strings referenced by the JavaPermission struct are passed to
+// the native part of the JDK. Avoid use of dynamically allocated strings
+// that could be de-allocated before the JDK native code had time to
+// convert them into Java Strings.
+struct JavaPermission {
+  const char* _class;
+  const char* _name;
+  const char* _action;
+};
+
 // CmdLine is the class used to handle a command line containing a single
 // diagnostic command and its arguments. It provides methods to access the
 // command name and the beginning of the arguments. The class is also
@@ -113,26 +129,30 @@
 // used to export the description to the JMX interface of the framework.
 class DCmdInfo : public ResourceObj {
 protected:
-  const char* _name;
-  const char* _description;
-  const char* _impact;
-  int         _num_arguments;
-  bool        _is_enabled;
+  const char* _name;           /* Name of the diagnostic command */
+  const char* _description;    /* Short description */
+  const char* _impact;         /* Impact on the JVM */
+  JavaPermission _permission;  /* Java Permission required to execute this command if any */
+  int         _num_arguments;  /* Number of supported options or arguments */
+  bool        _is_enabled;     /* True if the diagnostic command can be invoked, false otherwise */
 public:
   DCmdInfo(const char* name,
           const char* description,
           const char* impact,
+          JavaPermission permission,
           int num_arguments,
           bool enabled) {
     this->_name = name;
     this->_description = description;
     this->_impact = impact;
+    this->_permission = permission;
     this->_num_arguments = num_arguments;
     this->_is_enabled = enabled;
   }
   const char* name() const { return _name; }
   const char* description() const { return _description; }
   const char* impact() const { return _impact; }
+  JavaPermission permission() const { return _permission; }
   int num_arguments() const { return _num_arguments; }
   bool is_enabled() const { return _is_enabled; }
 
@@ -144,16 +164,20 @@
 // framework.
 class DCmdArgumentInfo : public ResourceObj {
 protected:
-  const char* _name;
-  const char* _description;
-  const char* _type;
-  const char* _default_string;
-  bool        _mandatory;
-  bool        _option;
-  int         _position;
+  const char* _name;            /* Option/Argument name*/
+  const char* _description;     /* Short description */
+  const char* _type;            /* Type: STRING, BOOLEAN, etc. */
+  const char* _default_string;  /* Default value in a parsable string */
+  bool        _mandatory;       /* True if the option/argument is mandatory */
+  bool        _option;          /* True if it is an option, false if it is an argument */
+                                /* (see diagnosticFramework.hpp for option/argument definitions) */
+  bool        _multiple;        /* True is the option can be specified several time */
+  int         _position;        /* Expected position for this argument (this field is */
+                                /* meaningless for options) */
 public:
   DCmdArgumentInfo(const char* name, const char* description, const char* type,
-                   const char* default_string, bool mandatory, bool option) {
+                   const char* default_string, bool mandatory, bool option,
+                   bool multiple) {
     this->_name = name;
     this->_description = description;
     this->_type = type;
@@ -161,11 +185,12 @@
     this->_option = option;
     this->_mandatory = mandatory;
     this->_option = option;
+    this->_multiple = multiple;
     this->_position = -1;
   }
   DCmdArgumentInfo(const char* name, const char* description, const char* type,
                    const char* default_string, bool mandatory, bool option,
-                   int position) {
+                   bool multiple, int position) {
     this->_name = name;
     this->_description = description;
     this->_type = type;
@@ -173,6 +198,7 @@
     this->_option = option;
     this->_mandatory = mandatory;
     this->_option = option;
+    this->_multiple = multiple;
     this->_position = position;
   }
   const char* name() const { return _name; }
@@ -181,11 +207,29 @@
   const char* default_string() const { return _default_string; }
   bool is_mandatory() const { return _mandatory; }
   bool is_option() const { return _option; }
+  bool is_multiple() const { return _multiple; }
   int position() const { return _position; }
 };
 
 // The DCmdParser class can be used to create an argument parser for a
 // diagnostic command. It is not mandatory to use it to parse arguments.
+// The DCmdParser parses a CmdLine instance according to the parameters that
+// have been declared by its associated diagnostic command. A parameter can
+// either be an option or an argument. Options are identified by the option name
+// while arguments are identified by their position in the command line. The
+// position of an argument is defined relative to all arguments passed on the
+// command line, options are not considered when defining an argument position.
+// The generic syntax of a diagnostic command is:
+//
+//    <command name> [<option>=<value>] [<argument_value>]
+//
+// Example:
+//
+//    command_name option1=value1 option2=value argumentA argumentB argumentC
+//
+// In this command line, the diagnostic command receives five parameters, two
+// options named option1 and option2, and three arguments. argumentA's position
+// is 0, argumentB's position is 1 and argumentC's position is 2.
 class DCmdParser {
 private:
   GenDCmdArgument* _options;
@@ -249,6 +293,19 @@
   // longer description can provide more specific details like the fact that Thread Dump
   // impact depends on the heap size.
   static const char* impact() { return "Low: No impact"; }
+  // The permission() method returns the description of Java Permission. This
+  // permission is required when the diagnostic command is invoked via the
+  // DiagnosticCommandMBean. The rationale for this permission check is that
+  // the DiagnosticCommandMBean can be used to perform remote invocations of
+  // diagnostic commands through the PlatformMBeanServer. The (optional) Java
+  // Permission associated with each diagnostic command should ease the work
+  // of system administrators to write policy files granting permissions to
+  // execute diagnostic commands to remote users. Any diagnostic command with
+  // a potential impact on security should overwrite this method.
+  static const JavaPermission permission() {
+    JavaPermission p = {NULL, NULL, NULL};
+    return p;
+  }
   static int num_arguments() { return 0; }
   outputStream* output() { return _output; }
   bool is_heap_allocated()  { return _is_heap_allocated; }
@@ -263,7 +320,7 @@
                 "The argument list of this diagnostic command should be empty.");
     }
   }
-  virtual void execute(TRAPS) { }
+  virtual void execute(DCmdSource source, TRAPS) { }
   virtual void reset(TRAPS) { }
   virtual void cleanup() { }
 
@@ -278,7 +335,7 @@
   }
 
   // main method to invoke the framework
-  static void parse_and_execute(outputStream* out, const char* cmdline,
+  static void parse_and_execute(DCmdSource source, outputStream* out, const char* cmdline,
                                 char delim, TRAPS);
 };
 
@@ -291,9 +348,10 @@
   static const char* description() { return "No Help";}
   static const char* disabled_message() { return "Diagnostic command currently disabled"; }
   static const char* impact() { return "Low: No impact"; }
+  static const JavaPermission permission() {JavaPermission p = {NULL, NULL, NULL}; return p; }
   static int num_arguments() { return 0; }
   virtual void parse(CmdLine *line, char delim, TRAPS);
-  virtual void execute(TRAPS) { }
+  virtual void execute(DCmdSource source, TRAPS) { }
   virtual void reset(TRAPS);
   virtual void cleanup();
   virtual void print_help(const char* name);
@@ -323,6 +381,8 @@
 class DCmdFactory: public CHeapObj<mtInternal> {
 private:
   static Mutex*       _dcmdFactory_lock;
+  static bool         _send_jmx_notification;
+  static bool         _has_pending_jmx_notification;
   // Pointer to the next factory in the singly-linked list of registered
   // diagnostic commands
   DCmdFactory*        _next;
@@ -333,19 +393,23 @@
   // When hidden, a diagnostic command doesn't appear in the list of commands
   // provided by the 'help' command.
   bool                _hidden;
+  uint32_t            _export_flags;
   int                 _num_arguments;
   static DCmdFactory* _DCmdFactoryList;
 public:
-  DCmdFactory(int num_arguments, bool enabled, bool hidden) {
+  DCmdFactory(int num_arguments, uint32_t flags, bool enabled, bool hidden) {
     _next = NULL;
     _enabled = enabled;
     _hidden = hidden;
+    _export_flags = flags;
     _num_arguments = num_arguments;
   }
   bool is_enabled() const { return _enabled; }
   void set_enabled(bool b) { _enabled = b; }
   bool is_hidden() const { return _hidden; }
   void set_hidden(bool b) { _hidden = b; }
+  uint32_t export_flags() { return _export_flags; }
+  void set_export_flags(uint32_t f) { _export_flags = f; }
   int num_arguments() { return _num_arguments; }
   DCmdFactory* next() { return _next; }
   virtual DCmd* create_Cheap_instance(outputStream* output) = 0;
@@ -353,19 +417,29 @@
   virtual const char* name() const = 0;
   virtual const char* description() const = 0;
   virtual const char* impact() const = 0;
+  virtual const JavaPermission permission() const = 0;
   virtual const char* disabled_message() const = 0;
   // Register a DCmdFactory to make a diagnostic command available.
   // Once registered, a diagnostic command must not be unregistered.
   // To prevent a diagnostic command from being executed, just set the
   // enabled flag to false.
   static int register_DCmdFactory(DCmdFactory* factory);
-  static DCmdFactory* factory(const char* cmd, size_t len);
+  static DCmdFactory* factory(DCmdSource source, const char* cmd, size_t len);
   // Returns a C-heap allocated diagnostic command for the given command line
-  static DCmd* create_global_DCmd(CmdLine &line, outputStream* out, TRAPS);
+  static DCmd* create_global_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
   // Returns a resourceArea allocated diagnostic command for the given command line
-  static DCmd* create_local_DCmd(CmdLine &line, outputStream* out, TRAPS);
-  static GrowableArray<const char*>* DCmd_list();
-  static GrowableArray<DCmdInfo*>* DCmdInfo_list();
+  static DCmd* create_local_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
+  static GrowableArray<const char*>* DCmd_list(DCmdSource source);
+  static GrowableArray<DCmdInfo*>* DCmdInfo_list(DCmdSource source);
+
+  static void set_jmx_notification_enabled(bool enabled) {
+    _send_jmx_notification = enabled;
+  }
+  static void push_jmx_notification_request();
+  static bool has_pending_jmx_notification() { return _has_pending_jmx_notification; }
+  static void send_notification(TRAPS);
+private:
+  static void send_notification_internal(TRAPS);
 
   friend class HelpDCmd;
 };
@@ -374,8 +448,8 @@
 // where this template is used to create and register factories.
 template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory {
 public:
-  DCmdFactoryImpl(bool enabled, bool hidden) :
-    DCmdFactory(DCmdClass::num_arguments(), enabled, hidden) { }
+  DCmdFactoryImpl(uint32_t flags, bool enabled, bool hidden) :
+    DCmdFactory(DCmdClass::num_arguments(), flags, enabled, hidden) { }
   // Returns a C-heap allocated instance
   virtual DCmd* create_Cheap_instance(outputStream* output) {
     return new (ResourceObj::C_HEAP, mtInternal) DCmdClass(output, true);
@@ -393,6 +467,9 @@
   virtual const char* impact() const {
     return DCmdClass::impact();
   }
+  virtual const JavaPermission permission() const {
+    return DCmdClass::permission();
+  }
   virtual const char* disabled_message() const {
      return DCmdClass::disabled_message();
   }
--- a/hotspot/src/share/vm/services/jmm.h	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/jmm.h	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,7 +49,8 @@
   JMM_VERSION_1_1 = 0x20010100, // JDK 6
   JMM_VERSION_1_2 = 0x20010200, // JDK 7
   JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
-  JMM_VERSION     = 0x20010202
+  JMM_VERSION_1_2_2 = 0x20010202,
+  JMM_VERSION     = 0x20010203
 };
 
 typedef struct {
@@ -62,7 +63,8 @@
   unsigned int isObjectMonitorUsageSupported : 1;
   unsigned int isSynchronizerUsageSupported : 1;
   unsigned int isThreadAllocatedMemorySupported : 1;
-  unsigned int : 23;
+  unsigned int isRemoteDiagnosticCommandsSupported : 1;
+  unsigned int : 22;
 } jmmOptionalSupport;
 
 typedef enum {
@@ -190,21 +192,27 @@
 } jmmGCStat;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* impact;
-  int         num_arguments;
-  jboolean    enabled;
+  const char* name;                /* Name of the diagnostic command */
+  const char* description;         /* Short description */
+  const char* impact;              /* Impact on the JVM */
+  const char* permission_class;    /* Class name of the required permission if any */
+  const char* permission_name;     /* Permission name of the required permission if any */
+  const char* permission_action;   /* Action name of the required permission if any*/
+  int         num_arguments;       /* Number of supported options or arguments */
+  jboolean    enabled;             /* True if the diagnostic command can be invoked, false otherwise */
 } dcmdInfo;
 
 typedef struct {
-  const char* name;
-  const char* description;
-  const char* type;
-  const char* default_string;
-  jboolean    mandatory;
-  jboolean    option;
-  int         position;
+  const char* name;                /* Option/Argument name*/
+  const char* description;         /* Short description */
+  const char* type;                /* Type: STRING, BOOLEAN, etc. */
+  const char* default_string;      /* Default value in a parsable string */
+  jboolean    mandatory;           /* True if the option/argument is mandatory */
+  jboolean    option;              /* True if it is an option, false if it is an argument */
+                                   /* (see diagnosticFramework.hpp for option/argument definitions) */
+  jboolean    multiple;            /* True if the option can be specified several time */
+  int         position;            /* Expected position for this argument (this field is */
+                                   /* meaningless for options) */
 } dcmdArgInfo;
 
 typedef struct jmmInterface_1_ {
@@ -327,6 +335,9 @@
   jstring      (JNICALL *ExecuteDiagnosticCommand)
                                                  (JNIEnv *env,
                                                   jstring command);
+  void         (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
+                                                 (JNIEnv *env,
+                                                  jboolean enabled);
 } JmmInterface;
 
 #ifdef __cplusplus
--- a/hotspot/src/share/vm/services/management.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/management.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -68,6 +68,9 @@
 Klass* Management::_managementFactory_klass = NULL;
 Klass* Management::_garbageCollectorImpl_klass = NULL;
 Klass* Management::_gcInfo_klass = NULL;
+Klass* Management::_diagnosticCommandImpl_klass = NULL;
+Klass* Management::_managementFactoryHelper_klass = NULL;
+
 
 jmmOptionalSupport Management::_optional_support = {0};
 TimeStamp Management::_stamp;
@@ -128,11 +131,14 @@
   _optional_support.isSynchronizerUsageSupported = 1;
 #endif // INCLUDE_SERVICES
   _optional_support.isThreadAllocatedMemorySupported = 1;
+  _optional_support.isRemoteDiagnosticCommandsSupported = 1;
 
   // Registration of the diagnostic commands
   DCmdRegistrant::register_dcmds();
   DCmdRegistrant::register_dcmds_ext();
-  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(true, false));
+  uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
+                         | DCmd_Source_MBean;
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(full_export, true, false));
 }
 
 void Management::initialize(TRAPS) {
@@ -262,6 +268,20 @@
   return _gcInfo_klass;
 }
 
+Klass* Management::sun_management_DiagnosticCommandImpl_klass(TRAPS) {
+  if (_diagnosticCommandImpl_klass == NULL) {
+    _diagnosticCommandImpl_klass = load_and_initialize_klass(vmSymbols::sun_management_DiagnosticCommandImpl(), CHECK_NULL);
+  }
+  return _diagnosticCommandImpl_klass;
+}
+
+Klass* Management::sun_management_ManagementFactoryHelper_klass(TRAPS) {
+  if (_managementFactoryHelper_klass == NULL) {
+    _managementFactoryHelper_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactoryHelper(), CHECK_NULL);
+  }
+  return _managementFactoryHelper_klass;
+}
+
 static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args, ThreadSnapshot* snapshot, TRAPS) {
   Handle snapshot_thread(THREAD, snapshot->threadObj());
 
@@ -2144,7 +2164,7 @@
 
 JVM_ENTRY(jobjectArray, jmm_GetDiagnosticCommands(JNIEnv *env))
   ResourceMark rm(THREAD);
-  GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list();
+  GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list(DCmd_Source_MBean);
   objArrayOop cmd_array_oop = oopFactory::new_objArray(SystemDictionary::String_klass(),
           dcmd_list->length(), CHECK_NULL);
   objArrayHandle cmd_array(THREAD, cmd_array_oop);
@@ -2173,7 +2193,7 @@
                "Array element type is not String class");
   }
 
-  GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list();
+  GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list(DCmd_Source_MBean);
 
   int num_cmds = cmds_ah->length();
   for (int i = 0; i < num_cmds; i++) {
@@ -2196,6 +2216,10 @@
     infoArray[i].name = info->name();
     infoArray[i].description = info->description();
     infoArray[i].impact = info->impact();
+    JavaPermission p = info->permission();
+    infoArray[i].permission_class = p._class;
+    infoArray[i].permission_name = p._name;
+    infoArray[i].permission_action = p._action;
     infoArray[i].num_arguments = info->num_arguments();
     infoArray[i].enabled = info->is_enabled();
   }
@@ -2215,7 +2239,8 @@
               "Command line content cannot be null.");
   }
   DCmd* dcmd = NULL;
-  DCmdFactory*factory = DCmdFactory::factory(cmd_name, strlen(cmd_name));
+  DCmdFactory*factory = DCmdFactory::factory(DCmd_Source_MBean, cmd_name,
+                                             strlen(cmd_name));
   if (factory != NULL) {
     dcmd = factory->create_resource_instance(NULL);
   }
@@ -2235,6 +2260,7 @@
     infoArray[i].default_string = array->at(i)->default_string();
     infoArray[i].mandatory = array->at(i)->is_mandatory();
     infoArray[i].option = array->at(i)->is_option();
+    infoArray[i].multiple = array->at(i)->is_multiple();
     infoArray[i].position = array->at(i)->position();
   }
   return;
@@ -2253,11 +2279,15 @@
                    "Command line content cannot be null.");
   }
   bufferedStream output;
-  DCmd::parse_and_execute(&output, cmdline, ' ', CHECK_NULL);
+  DCmd::parse_and_execute(DCmd_Source_MBean, &output, cmdline, ' ', CHECK_NULL);
   oop result = java_lang_String::create_oop_from_str(output.as_string(), CHECK_NULL);
   return (jstring) JNIHandles::make_local(env, result);
 JVM_END
 
+JVM_ENTRY(void, jmm_SetDiagnosticFrameworkNotificationEnabled(JNIEnv *env, jboolean enabled))
+  DCmdFactory::set_jmx_notification_enabled(enabled?true:false);
+JVM_END
+
 jlong Management::ticks_to_ms(jlong ticks) {
   assert(os::elapsed_frequency() > 0, "Must be non-zero");
   return (jlong)(((double)ticks / (double)os::elapsed_frequency())
@@ -2304,7 +2334,8 @@
   jmm_GetDiagnosticCommands,
   jmm_GetDiagnosticCommandInfo,
   jmm_GetDiagnosticCommandArgumentsInfo,
-  jmm_ExecuteDiagnosticCommand
+  jmm_ExecuteDiagnosticCommand,
+  jmm_SetDiagnosticFrameworkNotificationEnabled
 };
 #endif // INCLUDE_MANAGEMENT
 
--- a/hotspot/src/share/vm/services/management.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/management.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,6 +50,8 @@
   static Klass*             _garbageCollectorMXBean_klass;
   static Klass*             _managementFactory_klass;
   static Klass*             _garbageCollectorImpl_klass;
+  static Klass*             _diagnosticCommandImpl_klass;
+  static Klass*             _managementFactoryHelper_klass;
   static Klass*             _gcInfo_klass;
 
   static Klass* load_and_initialize_klass(Symbol* sh, TRAPS);
@@ -99,6 +101,10 @@
       NOT_MANAGEMENT_RETURN_(NULL);
   static Klass* com_sun_management_GcInfo_klass(TRAPS)
       NOT_MANAGEMENT_RETURN_(NULL);
+  static Klass* sun_management_DiagnosticCommandImpl_klass(TRAPS)
+      NOT_MANAGEMENT_RETURN_(NULL);
+  static Klass* sun_management_ManagementFactoryHelper_klass(TRAPS)
+      NOT_MANAGEMENT_RETURN_(NULL);
 
   static instanceOop create_thread_info_instance(ThreadSnapshot* snapshot, TRAPS);
   static instanceOop create_thread_info_instance(ThreadSnapshot* snapshot, objArrayHandle monitors_array, typeArrayHandle depths_array, objArrayHandle synchronizers_array, TRAPS);
--- a/hotspot/src/share/vm/services/memBaseline.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/memBaseline.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,9 +23,12 @@
  */
 #include "precompiled.hpp"
 #include "memory/allocation.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
 #include "services/memBaseline.hpp"
 #include "services/memTracker.hpp"
 
+
 MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = {
   {mtJavaHeap,   "Java Heap"},
   {mtClass,      "Class"},
@@ -149,6 +152,15 @@
   return true;
 }
 
+// check if there is a safepoint in progress, if so, block the thread
+// for the safepoint
+void MemBaseline::check_safepoint(JavaThread* thr) {
+  if (SafepointSynchronize::is_synchronizing()) {
+    // grab and drop the SR_lock to honor the safepoint protocol
+    MutexLocker ml(thr->SR_lock());
+  }
+}
+
 // baseline mmap'd memory records, generate overall summary and summaries by
 // memory types
 bool MemBaseline::baseline_vm_summary(const MemPointerArray* vm_records) {
@@ -306,7 +318,7 @@
         committed_rec->pc() != vm_ptr->pc()) {
         if (!_vm_map->append(vm_ptr)) {
           return false;
-  }
+        }
         committed_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1);
     } else {
         committed_rec->expand_region(vm_ptr->addr(), vm_ptr->size());
@@ -344,16 +356,27 @@
 
 // baseline a snapshot. If summary_only = false, memory usages aggregated by
 // callsites are also baselined.
+// The method call can be lengthy, especially when detail tracking info is
+// requested. So the method checks for safepoint explicitly.
 bool MemBaseline::baseline(MemSnapshot& snapshot, bool summary_only) {
-  MutexLockerEx snapshot_locker(snapshot._lock, true);
+  Thread* THREAD = Thread::current();
+  assert(THREAD->is_Java_thread(), "must be a JavaThread");
+  MutexLocker snapshot_locker(snapshot._lock);
   reset();
-  _baselined = baseline_malloc_summary(snapshot._alloc_ptrs) &&
-               baseline_vm_summary(snapshot._vm_ptrs);
+  _baselined = baseline_malloc_summary(snapshot._alloc_ptrs);
+  if (_baselined) {
+    check_safepoint((JavaThread*)THREAD);
+    _baselined = baseline_vm_summary(snapshot._vm_ptrs);
+  }
   _number_of_classes = snapshot.number_of_classes();
 
   if (!summary_only && MemTracker::track_callsite() && _baselined) {
-    _baselined =  baseline_malloc_details(snapshot._alloc_ptrs) &&
-      baseline_vm_details(snapshot._vm_ptrs);
+    check_safepoint((JavaThread*)THREAD);
+    _baselined =  baseline_malloc_details(snapshot._alloc_ptrs);
+    if (_baselined) {
+      check_safepoint((JavaThread*)THREAD);
+      _baselined =  baseline_vm_details(snapshot._vm_ptrs);
+    }
   }
   return _baselined;
 }
--- a/hotspot/src/share/vm/services/memBaseline.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/memBaseline.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -330,6 +330,9 @@
   // should not use copy constructor
   MemBaseline(MemBaseline& copy) { ShouldNotReachHere(); }
 
+  // check and block at a safepoint
+  static inline void check_safepoint(JavaThread* thr);
+
  public:
   // create a memory baseline
   MemBaseline();
--- a/hotspot/src/share/vm/services/memSnapshot.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/memSnapshot.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -262,13 +262,28 @@
   assert(cur->is_reserved_region() && cur->contains_region(rec),
     "Sanity check");
   if (rec->is_same_region(cur)) {
-    // release whole reserved region
+
+    // In snapshot, the virtual memory records are sorted in following orders:
+    // 1. virtual memory's base address
+    // 2. virtual memory reservation record, followed by commit records within this reservation.
+    //    The commit records are also in base address order.
+    // When a reserved region is released, we want to remove the reservation record and all
+    // commit records following it.
 #ifdef ASSERT
-    VMMemRegion* next_region = (VMMemRegion*)peek_next();
-    // should not have any committed memory in this reserved region
-    assert(next_region == NULL || !next_region->is_committed_region(), "Sanity check");
+    address low_addr = cur->addr();
+    address high_addr = low_addr + cur->size();
 #endif
+    // remove virtual memory reservation record
     remove();
+    // remove committed regions within above reservation
+    VMMemRegion* next_region = (VMMemRegion*)current();
+    while (next_region != NULL && next_region->is_committed_region()) {
+      assert(next_region->addr() >= low_addr &&
+             next_region->addr() + next_region->size() <= high_addr,
+            "Range check");
+      remove();
+      next_region = (VMMemRegion*)current();
+    }
   } else if (rec->addr() == cur->addr() ||
     rec->addr() + rec->size() == cur->addr() + cur->size()) {
     // released region is at either end of this region
--- a/hotspot/src/share/vm/services/memTracker.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/memTracker.cpp	Thu May 16 11:47:51 2013 +0100
@@ -573,7 +573,7 @@
 
 // baseline current memory snapshot
 bool MemTracker::baseline() {
-  MutexLockerEx lock(_query_lock, true);
+  MutexLocker lock(_query_lock);
   MemSnapshot* snapshot = get_snapshot();
   if (snapshot != NULL) {
     return _baseline.baseline(*snapshot, false);
@@ -584,7 +584,7 @@
 // print memory usage from current snapshot
 bool MemTracker::print_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
   MemBaseline  baseline;
-  MutexLockerEx lock(_query_lock, true);
+  MutexLocker  lock(_query_lock);
   MemSnapshot* snapshot = get_snapshot();
   if (snapshot != NULL && baseline.baseline(*snapshot, summary_only)) {
     BaselineReporter reporter(out, unit);
@@ -597,7 +597,7 @@
 // Whitebox API for blocking until the current generation of NMT data has been merged
 bool MemTracker::wbtest_wait_for_data_merge() {
   // NMT can't be shutdown while we're holding _query_lock
-  MutexLockerEx lock(_query_lock, true);
+  MutexLocker lock(_query_lock);
   assert(_worker_thread != NULL, "Invalid query");
   // the generation at query time, so NMT will spin till this generation is processed
   unsigned long generation_at_query_time = SequenceGenerator::current_generation();
@@ -641,7 +641,7 @@
 
 // compare memory usage between current snapshot and baseline
 bool MemTracker::compare_memory_usage(BaselineOutputer& out, size_t unit, bool summary_only) {
-  MutexLockerEx lock(_query_lock, true);
+  MutexLocker lock(_query_lock);
   if (_baseline.baselined()) {
     MemBaseline baseline;
     MemSnapshot* snapshot = get_snapshot();
--- a/hotspot/src/share/vm/services/nmtDCmd.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/nmtDCmd.cpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,7 +71,7 @@
   _dcmdparser.add_dcmd_option(&_scale);
 }
 
-void NMTDCmd::execute(TRAPS) {
+void NMTDCmd::execute(DCmdSource source, TRAPS) {
   const char* scale_value = _scale.value();
   size_t scale_unit;
   if (strcmp(scale_value, "KB") == 0 || strcmp(scale_value, "kb") == 0) {
--- a/hotspot/src/share/vm/services/nmtDCmd.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/services/nmtDCmd.hpp	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,10 +52,15 @@
     return "Print native memory usage";
   }
   static const char* impact() {
-    return "Medium:";
+    return "Medium";
+  }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+                        "monitor", NULL};
+    return p;
   }
   static int num_arguments();
-  virtual void execute(TRAPS);
+  virtual void execute(DCmdSource source, TRAPS);
 };
 
 #endif // SHARE_VM_SERVICES_NMT_DCMD_HPP
--- a/hotspot/src/share/vm/utilities/debug.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/debug.cpp	Thu May 16 11:47:51 2013 +0100
@@ -229,11 +229,11 @@
 }
 
 void report_vm_out_of_memory(const char* file, int line, size_t size,
-                             const char* message) {
+                             VMErrorType vm_err_type, const char* message) {
   if (Debugging) return;
 
   Thread* thread = ThreadLocalStorage::get_thread_slow();
-  VMError(thread, file, line, size, message).report_and_die();
+  VMError(thread, file, line, size, vm_err_type, message).report_and_die();
 
   // The UseOSErrorReporting option in report_and_die() may allow a return
   // to here. If so then we'll have to figure out how to handle it.
@@ -344,7 +344,7 @@
                            msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
                            msg, eol, msg, eol, msg, eol, msg, eol, msg, eol,
                            msg, eol, msg, eol, msg, eol, msg, eol, msg));
-    case  8: vm_exit_out_of_memory(num, "ChunkPool::allocate");
+    case  8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate");
     case  9: ShouldNotCallThis();
     case 10: ShouldNotReachHere();
     case 11: Unimplemented();
--- a/hotspot/src/share/vm/utilities/debug.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/debug.hpp	Thu May 16 11:47:51 2013 +0100
@@ -174,9 +174,9 @@
 } while (0)
 
 // out of memory
-#define vm_exit_out_of_memory(size, msg)                                     \
+#define vm_exit_out_of_memory(size, vm_err_type, msg)                        \
 do {                                                                         \
-  report_vm_out_of_memory(__FILE__, __LINE__, size, msg);                    \
+  report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, msg);       \
   BREAKPOINT;                                                                \
 } while (0)
 
@@ -204,12 +204,20 @@
   BREAKPOINT;                                                                \
 } while (0);
 
+
+// types of VM error - originally in vmError.hpp
+enum VMErrorType {
+  INTERNAL_ERROR   = 0xe0000000,
+  OOM_MALLOC_ERROR = 0xe0000001,
+  OOM_MMAP_ERROR   = 0xe0000002
+};
+
 // error reporting helper functions
 void report_vm_error(const char* file, int line, const char* error_msg,
                      const char* detail_msg = NULL);
 void report_fatal(const char* file, int line, const char* message);
 void report_vm_out_of_memory(const char* file, int line, size_t size,
-                             const char* message);
+                             VMErrorType vm_err_type, const char* message);
 void report_should_not_call(const char* file, int line);
 void report_should_not_reach_here(const char* file, int line);
 void report_unimplemented(const char* file, int line);
--- a/hotspot/src/share/vm/utilities/ostream.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/ostream.hpp	Thu May 16 11:47:51 2013 +0100
@@ -196,7 +196,7 @@
   fileStream() { _file = NULL; _need_close = false; }
   fileStream(const char* file_name);
   fileStream(const char* file_name, const char* opentype);
-  fileStream(FILE* file) { _file = file; _need_close = false; }
+  fileStream(FILE* file, bool need_close = false) { _file = file; _need_close = need_close; }
   ~fileStream();
   bool is_open() const { return _file != NULL; }
   void set_need_close(bool b) { _need_close = b;}
--- a/hotspot/src/share/vm/utilities/vmError.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/vmError.cpp	Thu May 16 11:47:51 2013 +0100
@@ -100,7 +100,7 @@
                  const char* message, const char * detail_msg)
 {
   _thread = thread;
-  _id = internal_error;     // Value that's not an OS exception/signal
+  _id = INTERNAL_ERROR;     // Value that's not an OS exception/signal
   _filename = filename;
   _lineno = lineno;
   _message = message;
@@ -119,9 +119,9 @@
 
 // Constructor for OOM errors
 VMError::VMError(Thread* thread, const char* filename, int lineno, size_t size,
-                 const char* message) {
+                 VMErrorType vm_err_type, const char* message) {
     _thread = thread;
-    _id = oom_error;     // Value that's not an OS exception/signal
+    _id = vm_err_type; // Value that's not an OS exception/signal
     _filename = filename;
     _lineno = lineno;
     _message = message;
@@ -142,7 +142,7 @@
 // Constructor for non-fatal errors
 VMError::VMError(const char* message) {
     _thread = NULL;
-    _id = internal_error;     // Value that's not an OS exception/signal
+    _id = INTERNAL_ERROR;     // Value that's not an OS exception/signal
     _filename = NULL;
     _lineno = 0;
     _message = message;
@@ -351,9 +351,12 @@
   STEP(15, "(printing type of error)")
 
      switch(_id) {
-       case oom_error:
+       case OOM_MALLOC_ERROR:
+       case OOM_MMAP_ERROR:
          if (_size) {
-           st->print("# Native memory allocation (malloc) failed to allocate ");
+           st->print("# Native memory allocation ");
+           st->print((_id == (int)OOM_MALLOC_ERROR) ? "(malloc) failed to allocate " :
+                                                 "(mmap) failed to map ");
            jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size);
            st->print(buf);
            st->print(" bytes");
@@ -386,7 +389,7 @@
            return;  // that's enough for the screen
          }
          break;
-       case internal_error:
+       case INTERNAL_ERROR:
        default:
          break;
      }
@@ -796,6 +799,56 @@
 VMError* volatile VMError::first_error = NULL;
 volatile jlong VMError::first_error_tid = -1;
 
+/** Expand a pattern into a buffer starting at pos and open a file using constructed path */
+static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) {
+  int fd = -1;
+  if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) {
+    fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666);
+  }
+  return fd;
+}
+
+/**
+ * Construct file name for a log file and return it's file descriptor.
+ * Name and location depends on pattern, default_pattern params and access
+ * permissions.
+ */
+static int prepare_log_file(const char* pattern, const char* default_pattern, char* buf, size_t buflen) {
+  int fd = -1;
+
+  // If possible, use specified pattern to construct log file name
+  if (pattern != NULL) {
+    fd = expand_and_open(pattern, buf, buflen, 0);
+  }
+
+  // Either user didn't specify, or the user's location failed,
+  // so use the default name in the current directory
+  if (fd == -1) {
+    const char* cwd = os::get_current_directory(buf, buflen);
+    if (cwd != NULL) {
+      size_t pos = strlen(cwd);
+      int fsep_len = jio_snprintf(&buf[pos], buflen-pos, "%s", os::file_separator());
+      pos += fsep_len;
+      if (fsep_len > 0) {
+        fd = expand_and_open(default_pattern, buf, buflen, pos);
+      }
+    }
+  }
+
+   // try temp directory if it exists.
+   if (fd == -1) {
+     const char* tmpdir = os::get_temp_directory();
+     if (tmpdir != NULL && strlen(tmpdir) > 0) {
+       int pos = jio_snprintf(buf, buflen, "%s%s", tmpdir, os::file_separator());
+       if (pos > 0) {
+         fd = expand_and_open(default_pattern, buf, buflen, pos);
+       }
+     }
+   }
+
+  return fd;
+}
+
 void VMError::report_and_die() {
   // Don't allocate large buffer on stack
   static char buffer[O_BUFLEN];
@@ -905,36 +958,7 @@
     // see if log file is already open
     if (!log.is_open()) {
       // open log file
-      int fd = -1;
-
-      if (ErrorFile != NULL) {
-        bool copy_ok =
-          Arguments::copy_expand_pid(ErrorFile, strlen(ErrorFile), buffer, sizeof(buffer));
-        if (copy_ok) {
-          fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
-        }
-      }
-
-      if (fd == -1) {
-        const char *cwd = os::get_current_directory(buffer, sizeof(buffer));
-        size_t len = strlen(cwd);
-        // either user didn't specify, or the user's location failed,
-        // so use the default name in the current directory
-        jio_snprintf(&buffer[len], sizeof(buffer)-len, "%shs_err_pid%u.log",
-                     os::file_separator(), os::current_process_id());
-        fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
-      }
-
-      if (fd == -1) {
-        const char * tmpdir = os::get_temp_directory();
-        // try temp directory if it exists.
-        if (tmpdir != NULL && tmpdir[0] != '\0') {
-          jio_snprintf(buffer, sizeof(buffer), "%s%shs_err_pid%u.log",
-                       tmpdir, os::file_separator(), os::current_process_id());
-          fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
-        }
-      }
-
+      int fd = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer));
       if (fd != -1) {
         out.print_raw("# An error report file with more information is saved as:\n# ");
         out.print_raw_cr(buffer);
@@ -958,7 +982,7 @@
     // Run error reporting to determine whether or not to report the crash.
     if (!transmit_report_done && should_report_bug(first_error->_id)) {
       transmit_report_done = true;
-      FILE* hs_err = ::fdopen(log.fd(), "r");
+      FILE* hs_err = os::open(log.fd(), "r");
       if (NULL != hs_err) {
         ErrorReporter er;
         er.call(hs_err, buffer, O_BUFLEN);
@@ -1008,7 +1032,19 @@
     skip_replay = true;
     ciEnv* env = ciEnv::current();
     if (env != NULL) {
-      env->dump_replay_data();
+      int fd = prepare_log_file(ReplayDataFile, "replay_pid%p.log", buffer, sizeof(buffer));
+      if (fd != -1) {
+        FILE* replay_data_file = os::open(fd, "w");
+        if (replay_data_file != NULL) {
+          fileStream replay_data_stream(replay_data_file, /*need_close=*/true);
+          env->dump_replay_data(&replay_data_stream);
+          out.print_raw("#\n# Compiler replay data is saved as:\n# ");
+          out.print_raw_cr(buffer);
+        } else {
+          out.print_raw("#\n# Can't open file to dump replay data. Error: ");
+          out.print_raw_cr(strerror(os::get_last_error()));
+        }
+      }
     }
   }
 
--- a/hotspot/src/share/vm/utilities/vmError.hpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/vmError.hpp	Thu May 16 11:47:51 2013 +0100
@@ -34,10 +34,6 @@
   friend class VM_ReportJavaOutOfMemory;
   friend class Decoder;
 
-  enum ErrorType {
-    internal_error = 0xe0000000,
-    oom_error      = 0xe0000001
-  };
   int          _id;          // Solaris/Linux signals: 0 - SIGRTMAX
                              // Windows exceptions: 0xCxxxxxxx system errors
                              //                     0x8xxxxxxx system warnings
@@ -96,9 +92,12 @@
   // accessor
   const char* message() const    { return _message; }
   const char* detail_msg() const { return _detail_msg; }
-  bool should_report_bug(unsigned int id) { return id != oom_error; }
+  bool should_report_bug(unsigned int id) {
+    return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR);
+  }
 
 public:
+
   // Constructor for crashes
   VMError(Thread* thread, unsigned int sig, address pc, void* siginfo,
           void* context);
@@ -108,7 +107,7 @@
 
   // Constructor for VM OOM errors
   VMError(Thread* thread, const char* filename, int lineno, size_t size,
-          const char* message);
+          VMErrorType vm_err_type, const char* message);
   // Constructor for non-fatal errors
   VMError(const char* message);
 
--- a/hotspot/src/share/vm/utilities/workgroup.cpp	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/src/share/vm/utilities/workgroup.cpp	Thu May 16 11:47:51 2013 +0100
@@ -79,7 +79,7 @@
   }
   _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal);
   if (gang_workers() == NULL) {
-    vm_exit_out_of_memory(0, "Cannot create GangWorker array.");
+    vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array.");
     return false;
   }
   os::ThreadType worker_type;
@@ -93,7 +93,8 @@
     assert(new_worker != NULL, "Failed to allocate GangWorker");
     _gang_workers[worker] = new_worker;
     if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
-      vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
+      vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
+              "Cannot create worker GC thread. Out of system resources.");
       return false;
     }
     if (!DisableStartThread) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestSA.sh	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,92 @@
+#!/bin/sh
+# 
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+# 
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+# 
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+# 
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+# 
+# 
+
+##
+## @test
+## @bug 8011675
+## @summary testing of ciReplay with using generated by SA replay.txt 
+## @author igor.ignatyev@oracle.com
+## @run shell TestSA.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+  TESTSRC=${PWD}
+  echo "TESTSRC not set.  Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+${MV} ${replay_data} replay_vm.txt    
+
+if [ -z "${core_file}" -o ! -r "${core_file}" ]
+then
+    # skip test if MacOS host isn't configured for core dumping
+    if [ "$OS" = "Darwin" ]
+    then
+        if [ ! -d "/cores" ]
+        then
+            echo TEST SKIPPED: \'/cores\' dir doens\'t exist
+            exit 0
+        fi
+        if [ ! -w "/cores" ]
+        then
+            echo TEST SKIPPED: \'/cores\' dir exists but is not writable
+            exit 0
+        fi
+    fi
+    test_fail 2 "CHECK :: CORE GENERATION" "core wasn't generated on $OS"
+fi
+
+echo "dumpreplaydata -a > ${replay_data}" | \
+        ${JAVA} ${TESTVMOPTS} \
+        -cp ${TESTJAVA}${FS}lib${FS}sa-jdi.jar \
+        sun.jvm.hotspot.CLHSDB  ${JAVA} ${core_file}
+
+if [ ! -s ${replay_data} ]
+then
+    test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+        "replay data wasn't generated by SA"
+fi
+
+diff --brief ${replay_data} replay_vm.txt
+if [ $? -ne 0 ]
+then
+    echo WARNING: replay.txt from SA != replay.txt from VM
+fi
+
+common_tests 10 
+${VM_TYPE}_tests 20
+
+cleanup
+
+echo TEST PASSED
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestVM.sh	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,86 @@
+#!/bin/sh
+# 
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+# 
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+# 
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+# 
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+# 
+# 
+
+##
+## @test
+## @bug 8011675
+## @summary testing of ciReplay with using generated by VM replay.txt 
+## @author igor.ignatyev@oracle.com
+## @run shell TestVM.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+  TESTSRC=${PWD}
+  echo "TESTSRC not set.  Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+if [ ! -s ${replay_data} ]
+then
+    test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+        "replay data wasn't generated by VM"
+fi
+
+common_tests 10
+${VM_TYPE}_tests 20
+
+cleanup
+
+if [ $is_tiered -eq 1 ]
+then
+    stop_level=1
+    while [ $stop_level -le $server_level ]
+    do
+        generate_replay "-XX:TieredStopAtLevel=$stop_level"
+        if [ ! -s ${replay_data} ]
+        then
+            test_fail `expr $stop_level + 30` \
+                    "TIERED LEVEL $stop_level :: REPLAY DATA GENERATION" \
+                    "replay data wasn't generated by VM with stop_level=$stop_level"
+        fi
+        level=`grep "^compile " $replay_data | awk '{print $6}'`
+        if [ $level -gt $stop_level ]
+        then
+            test_fail `expr $stop_level + 40` \
+                    "TIERED LEVEL $stop_level :: COMP_LEVEL VERIFICATION" \
+                    "comp_level in replay[$level] is greater than stop_level[$stop_level]"
+        fi
+        positive_test `expr $stop_level + 50` "TIERED LEVEL $stop_level :: REPLAY" \
+                "-XX:TieredStopAtLevel=$stop_level"
+        stop_level=`expr $stop_level + 1`
+    done
+    cleanup
+fi
+
+echo TEST PASSED
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,74 @@
+#!/bin/sh
+# 
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+# 
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+# 
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+# 
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+# 
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+# 
+# 
+
+##
+## @test
+## @bug 8011675
+## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level
+## @author igor.ignatyev@oracle.com
+## @run shell TestVM_no_comp_level.sh
+##
+
+if [ "${TESTSRC}" = "" ]
+then
+  TESTSRC=${PWD}
+  echo "TESTSRC not set.  Using "${TESTSRC}" as default"
+fi
+echo "TESTSRC=${TESTSRC}"
+
+## Adding common setup Variables for running shell tests.
+. ${TESTSRC}/../../test_env.sh
+
+. ${TESTSRC}/common.sh
+
+generate_replay
+
+if [ ! -s ${replay_data} ]
+then
+    test_fail 1 "CHECK :: REPLAY DATA GENERATION" \
+            "replay data wasn't generated by VM"
+fi
+
+${CP} ${replay_data} replay_vm.txt
+
+sed 's/^\(compile *[^ ][^ ]* *[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*\).*$/\1/' \
+        replay_vm.txt > ${replay_data}
+
+if [ $client_available -eq 1 ]
+then
+    # tiered is unavailable in client vm, so results w/ flags will be the same as w/o flags
+    negative_test 10 "CLIENT" -client
+fi
+
+if [ $server_available -eq 1 ]
+then
+    positive_test 21 "SERVER :: NON-TIERED" -XX:-TieredCompilation -server
+    positive_test 22 "SERVER :: TIERED" -XX:+TieredCompilation -server
+fi
+
+cleanup
+
+echo TEST PASSED
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/ciReplay/common.sh	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,253 @@
+#!/bin/sh
+# 
+# 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.
+# 
+# 
+
+# $1 - error code
+# $2 - test name
+# $3,.. - decription
+test_fail() {
+    error=$1
+    shift
+    name=$1
+    shift
+    echo "TEST [$name] FAILED:"
+    echo "$@"
+    exit $error
+}
+
+# $@ - additional vm opts
+start_test() {
+    # disable core dump on *nix
+    ulimit -S -c 0
+    # disable core dump on windows
+    VMOPTS="$@ -XX:-CreateMinidumpOnCrash"
+    cmd="${JAVA} ${VMOPTS} -XX:+ReplayCompiles -XX:ReplayDataFile=${replay_data}"
+    echo $cmd
+    $cmd
+    return $?
+}
+
+# $1 - error_code
+# $2 - test name
+# $3,.. - additional vm opts
+positive_test() {
+    error=$1
+    shift
+    name=$1
+    shift
+    VMOPTS="${TESTVMOPTS} $@"
+    echo "POSITIVE TEST [$name]"
+    start_test ${VMOPTS}
+    exit_code=$?
+    if [ ${exit_code} -ne 0 ]
+    then
+        test_fail $error "$name" "exit_code[${exit_code}] != 0 during replay "\
+                "w/ vmopts: ${VMOPTS}"
+    fi
+}
+
+# $1 - error_code
+# $2 - test name
+# $2,.. - additional vm opts
+negative_test() {
+    error=$1
+    shift
+    name=$1
+    shift
+    VMOPTS="${TESTVMOPTS} $@"
+    echo "NEGATIVE TEST [$name]"
+    start_test ${VMOPTS}
+    exit_code=$?
+    if [ ${exit_code} -eq 0 ]
+    then
+        test_fail $error "$name" "exit_code[${exit_code}] == 0 during replay "\
+                "w/ vmopts: ${VMOPTS}"
+    fi
+}
+
+# $1 - initial error_code
+common_tests() {
+    positive_test $1 "COMMON :: THE SAME FLAGS"
+    positive_test `expr $1 + 1` "COMMON :: TIERED" -XX:+TieredCompilation
+}
+
+# $1 - initial error_code
+# $2 - non-tiered comp_level 
+nontiered_tests() {
+    level=`grep "^compile " $replay_data | awk '{print $6}'`
+    # is level available in non-tiere
+    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
+}
+
+# $1 - initial error_code
+client_tests() {
+    # testing in opposite VM
+    if [ $server_available -eq 1 ]
+    then
+        negative_test $1 "SERVER :: NON-TIERED" -XX:-TieredCompilation \
+                -server
+        positive_test `expr $1 + 1` "SERVER :: TIERED" -XX:+TieredCompilation \
+                -server
+    fi
+    nontiered_tests `expr $1 + 2` $client_level 
+}
+
+# $1 - initial error_code
+server_tests() {
+    # testing in opposite VM
+    if [ $client_available -eq 1 ]
+    then
+        # tiered is unavailable in client vm, so results w/ flags will be the same as w/o flags
+        negative_test $1 "CLIENT" -client
+    fi
+    nontiered_tests `expr $1 + 2` $server_level
+}
+
+cleanup() {
+    ${RM} -f core*
+    ${RM} -f replay*.txt
+    ${RM} -f hs_err_pid*.log
+    ${RM} -f test_core
+    ${RM} -f test_replay.txt
+}
+
+JAVA=${TESTJAVA}${FS}bin${FS}java
+
+replay_data=test_replay.txt
+
+${JAVA} ${TESTVMOPTS} -Xinternalversion 2>&1 | grep debug
+
+# Only test fastdebug 
+if [ $? -ne 0 ]
+then
+    echo TEST SKIPPED: product build
+    exit 0
+fi
+
+is_int=`${JAVA} ${TESTVMOPTS} -version 2>&1 | grep -c "interpreted mode"`
+# Not applicable for Xint
+if [ $is_int -ne 0 ]
+then
+    echo TEST SKIPPED: interpreted mode
+    exit 0
+fi
+
+cleanup
+
+client_available=`${JAVA} ${TESTVMOPTS} -client -Xinternalversion 2>&1 | \
+        grep -c Client`
+server_available=`${JAVA} ${TESTVMOPTS} -server -Xinternalversion 2>&1 | \
+        grep -c Server`
+is_tiered=`${JAVA} ${TESTVMOPTS} -XX:+PrintFlagsFinal -version | \
+        grep TieredCompilation | \
+        grep -c true`
+# CompLevel_simple -- C1
+client_level=1
+# CompLevel_full_optimization -- C2 or Shark 
+server_level=4
+
+echo "client_available=$client_available"
+echo "server_available=$server_available"
+echo "is_tiered=$is_tiered"
+
+# crash vm in compiler thread with generation replay data and 'small' dump-file
+# $@ - additional vm opts
+generate_replay() {
+    # enable core dump
+    ulimit -c unlimited
+
+    cmd="${JAVA} ${TESTVMOPTS} $@ \
+            -Xms8m \
+            -Xmx32m \
+            -XX:MetaspaceSize=4m \
+            -XX:MaxMetaspaceSize=16m \
+            -XX:InitialCodeCacheSize=512k \
+            -XX:ReservedCodeCacheSize=4m \
+            -XX:ThreadStackSize=512 \
+            -XX:VMThreadStackSize=512 \
+            -XX:CompilerThreadStackSize=512 \
+            -XX:ParallelGCThreads=1 \
+            -XX:CICompilerCount=1 \
+            -Xcomp \
+            -XX:CICrashAt=1 \
+            -XX:+CreateMinidumpOnCrash \
+            -XX:+DumpReplayDataOnError \
+            -XX:ReplayDataFile=${replay_data} \
+            -version"
+    echo GENERATION OF REPLAY.TXT:
+    echo $cmd
+
+    ${cmd} 2>&1 > crash.out
+    
+    core_locations=`grep -i core crash.out | grep "location:" | \
+            sed -e 's/.*location: //'`
+    rm crash.out 
+    # processing core locations for *nix
+    if [ $OS != "windows" ]
+    then
+        # remove 'or' between '/core.<pid>' and 'core'
+        core_locations=`echo $core_locations | \
+                sed -e 's/\([^ ]*\) or \([^ ]*\)/\1 \2/'`
+        # add <core_path>/core.<pid> core.<pid>
+        core=`echo $core_locations | awk '{print $1}'`
+        dir=`dirname $core`
+        core=`basename $core`
+        if [ -n ${core} ]
+        then
+            core_locations="$core_locations $dir${FS}$core"
+        fi
+        core=`echo $core_locations | awk '{print $2}'`
+        if [ -n ${core} ]
+        then
+            core_locations="$core_locations $dir${FS}$core"
+        fi
+    fi
+
+    echo "LOOKING FOR CORE IN ${core_locations}"
+    for core in $core_locations
+    do
+        if [ -r "$core" ]
+        then
+            core_file=$core
+        fi
+    done
+
+    # core-file was found
+    if [ -n "$core_file" ]
+    then
+        ${MV} "${core_file}" test_core
+        core_file=test_core
+    fi
+
+    ${RM} -f hs_err_pid*.log
+}
+
--- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java	Thu May 16 11:47:51 2013 +0100
@@ -42,6 +42,11 @@
     protected static int COMP_LEVEL_NONE = 0;
     /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */
     protected static int COMP_LEVEL_ANY = -1;
+    /** {@code CompLevel::CompLevel_simple} -- C1 */
+    protected static int COMP_LEVEL_SIMPLE = 1;
+    /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */
+    protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4;
+
     /** Instance of WhiteBox */
     protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     /** Value of {@code -XX:CompileThreshold} */
@@ -91,6 +96,17 @@
         return result == null ? defaultValue : result;
     }
 
+    /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */
+    protected static boolean isC1Compile(int compLevel) {
+        return (compLevel > COMP_LEVEL_NONE)
+                && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION);
+    }
+
+    /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */
+    protected static boolean isC2Compile(int compLevel) {
+        return compLevel == COMP_LEVEL_FULL_OPTIMIZATION;
+    }
+
     /** tested method */
     protected final Executable method;
     private final Callable<Integer> callable;
--- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java	Thu May 16 11:47:51 2013 +0100
@@ -23,6 +23,7 @@
 
 /*
  * @test MakeMethodNotCompilableTest
+ * @bug 8012322
  * @library /testlibrary /testlibrary/whitebox
  * @build MakeMethodNotCompilableTest
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -67,28 +68,69 @@
         }
 
         if (TIERED_COMPILATION) {
-            for (int i = 1, n = TIERED_STOP_AT_LEVEL + 1; i < n; ++i) {
-                WHITE_BOX.makeMethodNotCompilable(method, i);
-                if (WHITE_BOX.isMethodCompilable(method, i)) {
+            final int tierLimit = TIERED_STOP_AT_LEVEL + 1;
+            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+                testTier(testedTier);
+            }
+            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
+                WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+                if (WHITE_BOX.isMethodCompilable(method, testedTier)) {
                     throw new RuntimeException(method
-                            + " must be not compilable at level" + i);
+                            + " must be not compilable at level" + testedTier);
                 }
-                WHITE_BOX.enqueueMethodForCompilation(method, i);
+                WHITE_BOX.enqueueMethodForCompilation(method, testedTier);
                 checkNotCompiled();
 
                 if (!WHITE_BOX.isMethodCompilable(method)) {
                     System.out.println(method
-                            + " is not compilable after level " + i);
+                            + " is not compilable after level " + testedTier);
                 }
             }
+        } else {
+            compile();
+            checkCompiled();
+            int compLevel = WHITE_BOX.getMethodCompilationLevel(method);
+            WHITE_BOX.deoptimizeMethod(method);
+            WHITE_BOX.makeMethodNotCompilable(method, compLevel);
+            if (WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                throw new RuntimeException(method
+                        + " must be not compilable at CompLevel::CompLevel_any,"
+                        + " after it is not compilable at " + compLevel);
+            }
+            WHITE_BOX.clearMethodState(method);
+
+            // nocompilable at opposite level must make no sense
+            int oppositeLevel;
+            if (isC1Compile(compLevel)) {
+              oppositeLevel = COMP_LEVEL_FULL_OPTIMIZATION;
+            } else {
+              oppositeLevel = COMP_LEVEL_SIMPLE;
+            }
+            WHITE_BOX.makeMethodNotCompilable(method, oppositeLevel);
+
+            if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                  throw new RuntimeException(method
+                        + " must be compilable at CompLevel::CompLevel_any,"
+                        + " even it is not compilable at opposite level ["
+                        + compLevel + "]");
+            }
 
-            // WB.clearMethodState() must reset no-compilable flags
-            WHITE_BOX.clearMethodState(method);
-            if (!WHITE_BOX.isMethodCompilable(method)) {
-                throw new RuntimeException(method
-                        + " is not compilable after clearMethodState()");
+            if (!WHITE_BOX.isMethodCompilable(method, compLevel)) {
+                  throw new RuntimeException(method
+                        + " must be compilable at level " + compLevel
+                        + ", even it is not compilable at opposite level ["
+                        + compLevel + "]");
             }
         }
+
+        // clearing after tiered/non-tiered tests
+        // WB.clearMethodState() must reset no-compilable flags
+        WHITE_BOX.clearMethodState(method);
+        if (!WHITE_BOX.isMethodCompilable(method)) {
+            throw new RuntimeException(method
+                    + " is not compilable after clearMethodState()");
+        }
+
         WHITE_BOX.makeMethodNotCompilable(method);
         if (WHITE_BOX.isMethodCompilable(method)) {
             throw new RuntimeException(method + " must be not compilable");
@@ -108,4 +150,65 @@
         compile();
         checkCompiled();
     }
+
+    // separately tests each tier
+    private void testTier(int testedTier) {
+        if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+            throw new RuntimeException(method
+                    + " is not compilable on start");
+        }
+        WHITE_BOX.makeMethodNotCompilable(method, testedTier);
+
+        // tests for all other tiers
+        for (int anotherTier = 1, tierLimit = TIERED_STOP_AT_LEVEL + 1;
+                    anotherTier < tierLimit; ++anotherTier) {
+            boolean isCompilable = WHITE_BOX.isMethodCompilable(method,
+                    anotherTier);
+            if (sameCompile(testedTier, anotherTier)) {
+                if (isCompilable) {
+                    throw new RuntimeException(method
+                            + " must be not compilable at level " + anotherTier
+                            + ", if it is not compilable at " + testedTier);
+                }
+                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+                checkNotCompiled();
+            } else {
+                if (!isCompilable) {
+                    throw new RuntimeException(method
+                            + " must be compilable at level " + anotherTier
+                            + ", even if it is not compilable at "
+                            + testedTier);
+                }
+                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier);
+                checkCompiled();
+                WHITE_BOX.deoptimizeMethod(method);
+            }
+
+            if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) {
+                throw new RuntimeException(method
+                        + " must be compilable at 'CompLevel::CompLevel_any'"
+                        + ", if it is not compilable only at " + testedTier);
+            }
+        }
+
+        // clear state after test
+        WHITE_BOX.clearMethodState(method);
+        if (!WHITE_BOX.isMethodCompilable(method, testedTier)) {
+            throw new RuntimeException(method
+                    + " is not compilable after clearMethodState()");
+        }
+    }
+
+    private boolean sameCompile(int level1, int level2) {
+        if (level1 == level2) {
+            return true;
+        }
+        if (isC1Compile(level1) && isC1Compile(level2)) {
+            return true;
+        }
+        if (isC2Compile(level1) && isC2Compile(level2)) {
+            return true;
+        }
+        return false;
+    }
 }
--- a/hotspot/test/gc/7072527/TestFullGCCount.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/test/gc/7072527/TestFullGCCount.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,71 +25,67 @@
  * @test TestFullGCount.java
  * @bug 7072527
  * @summary CMS: JMM GC counters overcount in some cases
- * @run main/othervm -XX:+UseConcMarkSweepGC TestFullGCCount
- *
+ * @run main/othervm -XX:+PrintGC TestFullGCCount
  */
 import java.util.*;
 import java.lang.management.*;
 
+/*
+ * Originally for a specific failure in CMS, this test now monitors all
+ * collectors for double-counting of collections.
+ */
 public class TestFullGCCount {
 
-    public String collectorName = "ConcurrentMarkSweep";
-
-    public static void main(String [] args) {
+    static List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
 
-        TestFullGCCount t = null;
-        if (args.length==2) {
-            t = new TestFullGCCount(args[0], args[1]);
-        } else {
-            t = new TestFullGCCount();
+    public static void main(String[] args) {
+        int iterations = 20;
+        boolean failed = false;
+        String errorMessage = "";
+        HashMap<String, List> counts = new HashMap<String, List>();
+
+        // Prime the collection of count lists for all collectors.
+        for (int i = 0; i < collectors.size(); i++) {
+            GarbageCollectorMXBean collector = collectors.get(i);
+            counts.put(collector.getName(), new ArrayList<Long>(iterations));
         }
-        System.out.println("Monitoring collector: " + t.collectorName);
-        t.run();
-    }
 
-    public TestFullGCCount(String pool, String collector) {
-        collectorName = collector;
-    }
-
-    public TestFullGCCount() {
-    }
+        // Perform some gc, record collector counts.
+        for (int i = 0; i < iterations; i++) {
+            System.gc();
+            addCollectionCount(counts, i);
+        }
 
-    public void run() {
-        int count = 0;
-        int iterations = 20;
-        long counts[] = new long[iterations];
-        boolean diffAlways2 = true; // assume we will fail
+        // Check the increments:
+        //   Old gen collectors should increase by one,
+        //   New collectors may or may not increase.
+        //   Any increase >=2 is unexpected.
+        for (String collector : counts.keySet()) {
+            System.out.println("Checking: " + collector);
 
-        for (int i=0; i<iterations; i++) {
-            System.gc();
-            counts[i] = getCollectionCount();
-            if (i>0) {
-                if (counts[i] - counts[i-1] != 2) {
-                    diffAlways2 = false;
+            for (int i = 0; i < iterations - 1; i++) {
+                List<Long> theseCounts = counts.get(collector);
+                long a = theseCounts.get(i);
+                long b = theseCounts.get(i + 1);
+                if (b - a >= 2) {
+                    failed = true;
+                    errorMessage += "Collector '" + collector + "' has increment " + (b - a) +
+                                    " at iteration " + i + "\n";
                 }
             }
         }
-        if (diffAlways2) {
-            throw new RuntimeException("FAILED: System.gc must be incrementing count twice.");
+        if (failed) {
+            System.err.println(errorMessage);
+            throw new RuntimeException("FAILED: System.gc collections miscounted.");
         }
         System.out.println("Passed.");
     }
 
-    private long getCollectionCount() {
-        long count = 0;
-        List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
-        List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
-        for (int i=0; i<collectors.size(); i++) {
+    private static void addCollectionCount(HashMap<String, List> counts, int iteration) {
+        for (int i = 0; i < collectors.size(); i++) {
             GarbageCollectorMXBean collector = collectors.get(i);
-            String name = collector.getName();
-            if (name.contains(collectorName)) {
-                System.out.println(name + ": collection count = "
-                                   + collector.getCollectionCount());
-                count = collector.getCollectionCount();
-            }
+            List thisList = counts.get(collector.getName());
+            thisList.add(collector.getCollectionCount());
         }
-        return count;
     }
-
 }
-
--- a/hotspot/test/gc/TestVerifyDuringStartup.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/test/gc/TestVerifyDuringStartup.java	Thu May 16 11:47:51 2013 +0100
@@ -23,22 +23,43 @@
 
 /* @test TestVerifyDuringStartup.java
  * @key gc
- * @bug 8010463
+ * @bug 8010463 8011343 8011898
  * @summary Simple test run with -XX:+VerifyDuringStartup -XX:-UseTLAB to verify 8010463
  * @library /testlibrary
  */
 
+import com.oracle.java.testlibrary.JDKToolFinder;
 import com.oracle.java.testlibrary.OutputAnalyzer;
 import com.oracle.java.testlibrary.ProcessTools;
+import java.util.ArrayList;
+import java.util.Collections;
 
 public class TestVerifyDuringStartup {
   public static void main(String args[]) throws Exception {
+    ArrayList<String> vmOpts = new ArrayList();
+
+    String testVmOptsStr = System.getProperty("test.java.opts");
+    if (!testVmOptsStr.isEmpty()) {
+      String[] testVmOpts = testVmOptsStr.split(" ");
+      Collections.addAll(vmOpts, testVmOpts);
+    }
+    Collections.addAll(vmOpts, new String[] {"-XX:-UseTLAB",
+                                             "-XX:+UnlockDiagnosticVMOptions",
+                                             "-XX:+VerifyDuringStartup",
+                                             "-version"});
+
+    System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+    for (int i = 0; i < vmOpts.size(); i += 1) {
+      System.out.print(" " + vmOpts.get(i));
+    }
+    System.out.println();
+
     ProcessBuilder pb =
-      ProcessTools.createJavaProcessBuilder(System.getProperty("test.vm.opts"),
-                                            "-XX:-UseTLAB",
-                                            "-XX:+UnlockDiagnosticVMOptions",
-                                            "-XX:+VerifyDuringStartup", "-version");
+      ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()]));
     OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+    System.out.println("Output:\n" + output.getOutput());
+
     output.shouldContain("[Verifying");
     output.shouldHaveExitValue(0);
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/concurrentMarkSweep/CheckAllocateAndSystemGC.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test CheckAllocateAndSystemGC
+ * @summary CMS: assert(used() == used_after_gc && used_after_gc <= capacity()) failed: used: 0 used_after_gc: 292080 capacity: 1431699456
+ * @bug 8013032
+ * @key gc
+ * @key regression
+ * @library /testlibrary
+ * @run main/othervm CheckAllocateAndSystemGC
+ * @author jon.masamitsu@oracle.com
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class CheckAllocateAndSystemGC {
+  public static void main(String args[]) throws Exception {
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+      "-showversion",
+      "-XX:+UseConcMarkSweepGC",
+      "-Xmn4m",
+      "-XX:MaxTenuringThreshold=1",
+      "-XX:-UseCMSCompactAtFullCollection",
+      "CheckAllocateAndSystemGC$AllocateAndSystemGC"
+      );
+
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+    output.shouldNotContain("error");
+
+    output.shouldHaveExitValue(0);
+  }
+  static class AllocateAndSystemGC {
+    public static void main(String [] args) {
+      Integer x[] = new Integer [1000];
+      // Allocate enough objects to cause a minor collection.
+      // These allocations suffice for a 4m young geneneration.
+      for (int i = 0; i < 100; i++) {
+        Integer y[] = new Integer[10000];
+      }
+      System.gc();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/concurrentMarkSweep/GuardShrinkWarning.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test GuardShrinkWarning
+ * @summary Remove warning about CMS generation shrinking.
+ * @bug 8012111
+ * @key gc
+ * @key regression
+ * @library /testlibrary
+ * @run main/othervm GuardShrinkWarning
+ * @author jon.masamitsu@oracle.com
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class GuardShrinkWarning {
+  public static void main(String args[]) throws Exception {
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+      "-showversion",
+      "-XX:+UseConcMarkSweepGC",
+      "-XX:+ExplicitGCInvokesConcurrent",
+      "GuardShrinkWarning$SystemGCCaller"
+      );
+
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+    output.shouldNotContain("Shrinking of CMS not yet implemented");
+
+    output.shouldNotContain("error");
+
+    output.shouldHaveExitValue(0);
+  }
+  static class SystemGCCaller {
+    public static void main(String [] args) {
+      System.gc();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/concurrentMarkSweep/SystemGCOnForegroundCollector.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test SystemGCOnForegroundCollector
+ * @summary CMS: Call reset_after_compaction() only if a compaction has been done
+ * @bug 8013184
+ * @key gc
+ * @key regression
+ * @library /testlibrary
+ * @run main/othervm SystemGCOnForegroundCollector
+ * @author jon.masamitsu@oracle.com
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class SystemGCOnForegroundCollector {
+  public static void main(String args[]) throws Exception {
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+      "-showversion",
+      "-XX:+UseConcMarkSweepGC",
+      "-XX:MaxTenuringThreshold=1",
+      "-XX:-UseCMSCompactAtFullCollection",
+      ThreePlusMSSystemGC.class.getName()
+      );
+
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+    output.shouldNotContain("error");
+
+    output.shouldHaveExitValue(0);
+  }
+
+  static class ThreePlusMSSystemGC {
+    public static void main(String [] args) {
+      // From running this test 3 System.gc() were always
+      // enough to see the failure but the cause of the failure
+      // depends on how objects are allocated in the CMS generation
+      // which is non-deterministic.  Use 30 iterations for a more
+      // reliable test.
+      for (int i = 0; i < 30; i++) {
+        System.gc();
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestRegionAlignment.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestRegionAlignment.java
+ * @bug 8013791
+ * @summary Make sure that G1 ergonomics pick a heap size that is aligned with the region size
+ * @run main/othervm -XX:+UseG1GC -XX:G1HeapRegionSize=32m -XX:MaxRAM=555m TestRegionAlignment
+ *
+ * When G1 ergonomically picks a maximum heap size it must be aligned to the region size.
+ * This test tries to get the VM to pick a small and unaligned heap size (by using MaxRAM=555) and a
+ * large region size (by using -XX:G1HeapRegionSize=32m). This will fail without the fix for 8013791.
+ */
+public class TestRegionAlignment {
+    public static void main(String[] args) { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestShrinkToOneRegion.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestShrinkToOneRegion.java
+ * @bug 8013872
+ * @summary Shrinking the heap down to one region used to hit an assert
+ * @run main/othervm -XX:+UseG1GC -XX:G1HeapRegionSize=32m -Xmx256m TestShrinkToOneRegion
+ *
+ * Doing a System.gc() without having allocated many objects will shrink the heap.
+ * With a large region size we will shrink the heap to one region.
+ */
+public class TestShrinkToOneRegion {
+    public static void main(String[] args) {
+        System.gc();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveClass.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveClass
+ * @summary This test case uses a java.lang.Class instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveClass test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClass
+ */
+
+import java.lang.ref.SoftReference;
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveClass {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    o = null; cl = null;
+    escape = c;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    c = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClass (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveClassLoader.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveClassLoader
+ * @summary This test case uses a java.lang.ClassLoader instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveClassLoader test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveClassLoader
+ */
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveClassLoader {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    o = null; c = null;
+    escape = cl;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    cl = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testClassLoader (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveObject.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveObject
+ * @summary This test case uses a class instance to keep the class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveObject test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveObject
+ */
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveObject {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+  public static Object escape = null;
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    cl = null; c = null;
+    escape = o;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (1) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (2) alive: " + isAlive);
+
+        ClassUnloadCommon.failIf(!isAlive, "should be alive");
+    }
+    o = null;
+    escape = null;
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testObject (3) alive: " + isAlive);
+        ClassUnloadCommon.failIf(isAlive, "should be unloaded");
+    }
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/KeepAliveSoftReference.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test KeepAliveSoftReference
+ * @summary This test case uses a java.lang.ref.SoftReference referencing a class instance to keep a class alive.
+ * @library /testlibrary /testlibrary/whitebox /runtime/testlibrary
+ * @library classes
+ * @build KeepAliveSoftReference test.Empty
+ * @build ClassUnloadCommon
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI KeepAliveSoftReference
+ */
+
+import java.lang.ref.SoftReference;
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are not unloaded when specific types of references are kept to them.
+ */
+public class KeepAliveSoftReference {
+  private static final String className = "test.Empty";
+  private static final WhiteBox wb = WhiteBox.getWhiteBox();
+
+  public static void main(String... args) throws Exception {
+    ClassLoader cl = ClassUnloadCommon.newClassLoader();
+    Class<?> c = cl.loadClass(className);
+    Object o = c.newInstance();
+    SoftReference<Object> sr = new SoftReference(o);
+    o = null; c = null; cl = null;
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (1) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (2) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+    sr.clear();
+    ClassUnloadCommon.triggerUnloading();
+
+    {
+        boolean isAlive = wb.isClassAlive(className);
+        System.out.println("testSoftReference (3) alive: " + isAlive);
+        boolean cleared = (sr.get() == null);
+        boolean shouldBeAlive = !cleared;
+        ClassUnloadCommon.failIf(isAlive != shouldBeAlive, "" + isAlive + " != " + shouldBeAlive);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/UnloadTest.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test UnloadTest
+ * @library /runtime/testlibrary /testlibrary /testlibrary/whitebox
+ * @library classes
+ * @build ClassUnloadCommon test.Empty
+ * @build UnloadTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -Xmn8m -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI UnloadTest
+ */
+import sun.hotspot.WhiteBox;
+
+/**
+ * Test that verifies that classes are unloaded when they are no longer reachable.
+ *
+ * The test creates a class loader, uses the loader to load a class and creates an instance
+ * of that class. The it nulls out all the references to the instance, class and class loader
+ * and tries to trigger class unloading. Then it verifies that the class is no longer
+ * loaded by the VM.
+ */
+public class UnloadTest {
+    private static String className = "test.Empty";
+
+    public static void main(String... args) throws Exception {
+       run();
+    }
+
+    private static void run() throws Exception {
+        final WhiteBox wb = WhiteBox.getWhiteBox();
+
+        ClassUnloadCommon.failIf(wb.isClassAlive(className), "is not expected to be alive yet");
+
+        ClassLoader cl = ClassUnloadCommon.newClassLoader();
+        Class<?> c = cl.loadClass(className);
+        Object o = c.newInstance();
+
+        ClassUnloadCommon.failIf(!wb.isClassAlive(className), "should be live here");
+
+        cl = null; c = null; o = null;
+        ClassUnloadCommon.triggerUnloading();
+        ClassUnloadCommon.failIf(wb.isClassAlive(className), "should have been unloaded");
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassUnload/classes/test/Empty.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,5 @@
+package test;
+
+public class Empty {
+public String toString() { return "nothing"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/NMT/ReleaseCommittedMemory.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8013120
+ * @summary Release committed memory and make sure NMT handles it correctly
+ * @key nmt regression
+ * @library /testlibrary /testlibrary/whitebox
+ * @build ReleaseCommittedMemory
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail ReleaseCommittedMemory
+ */
+
+import sun.hotspot.WhiteBox;
+
+public class ReleaseCommittedMemory {
+
+  public static void main(String args[]) throws Exception {
+    WhiteBox wb = WhiteBox.getWhiteBox();
+    long reserveSize = 256 * 1024;
+    long addr;
+
+    addr = wb.NMTReserveMemory(reserveSize);
+    wb.NMTCommitMemory(addr, 128*1024);
+    wb.NMTReleaseMemory(addr, reserveSize);
+    wb.NMTWaitForDataMerge();
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/lambda-features/PublicStaticInterfaceMethodHandling.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8013418
+ * @summary [JDK 8] Test correct handling of static public interface methods
+ * @run main/othervm -Xverify:all PublicStaticInterfaceMethodHandling
+ */
+
+class TestClass implements InterfaceWithStaticAndDefaultMethods {
+}
+
+interface InterfaceWithStaticAndDefaultMethods {
+    public static String get() {
+        return "Hello from StaticMethodInInterface.get()";
+    }
+    default void default_method() {
+        System.out.println("Default method FunctionalInterface:default_method()");
+    }
+}
+
+public class PublicStaticInterfaceMethodHandling  {
+    public static void main(String[] args) {
+        TestClass tc = new TestClass();
+        tc.default_method();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/memory/ReserveMemory.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @key regression
+ * @bug 8012015
+ * @summary Make sure reserved (but uncommitted) memory is not accessible
+ * @library /testlibrary /testlibrary/whitebox
+ * @build ReserveMemory
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main ReserveMemory
+ */
+
+import com.oracle.java.testlibrary.*;
+
+import java.lang.reflect.Field;
+import sun.hotspot.WhiteBox;
+import sun.misc.Unsafe;
+
+public class ReserveMemory {
+  private static Unsafe getUnsafe() throws Exception {
+    Field f = Unsafe.class.getDeclaredField("theUnsafe");
+    f.setAccessible(true);
+    return (Unsafe)f.get(null);
+  }
+
+  private static boolean isWindows() {
+    return System.getProperty("os.name").toLowerCase().startsWith("win");
+  }
+
+  public static void main(String args[]) throws Exception {
+    if (args.length > 0) {
+      long address = WhiteBox.getWhiteBox().reserveMemory(4096);
+
+      System.out.println("Reserved memory at address: 0x" + Long.toHexString(address));
+      System.out.println("Will now read from the address, expecting a crash!");
+
+      int x = getUnsafe().getInt(address);
+
+      throw new Exception("Read of reserved/uncommitted memory unexpectedly succeeded, expected crash!");
+    }
+
+    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+          "-Xbootclasspath/a:.",
+          "-XX:+UnlockDiagnosticVMOptions",
+          "-XX:+WhiteBoxAPI",
+          "ReserveMemory",
+          "test");
+
+    OutputAnalyzer output = new OutputAnalyzer(pb.start());
+    if (isWindows()) {
+      output.shouldContain("EXCEPTION_ACCESS_VIOLATION");
+    } else {
+      output.shouldContain("SIGSEGV");
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/testlibrary/ClassUnloadCommon.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+
+public class ClassUnloadCommon {
+    public static class TestFailure extends RuntimeException {
+        TestFailure(String msg) {
+            super(msg);
+        }
+    }
+
+    public static void failIf(boolean value, String msg) {
+        if (value) throw new TestFailure("Test failed: " + msg);
+    }
+
+    private static volatile Object dummy = null;
+    private static void allocateMemory(int kilobytes) {
+        ArrayList<byte[]> l = new ArrayList<>();
+        dummy = l;
+        for (int i = kilobytes; i > 0; i -= 1) {
+            l.add(new byte[1024]);
+        }
+        l = null;
+        dummy = null;
+    }
+
+    public static void triggerUnloading() {
+        allocateMemory(16 * 1024); // yg size is 8m with cms, force young collection
+        System.gc();
+    }
+
+    public static ClassLoader newClassLoader() {
+        try {
+            return new URLClassLoader(new URL[] {
+                Paths.get(System.getProperty("test.classes",".") + File.separatorChar + "classes").toUri().toURL(),
+            }, null);
+        } catch (MalformedURLException e){
+            throw new RuntimeException("Unexpected URL conversion failure", e);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/sanity/WhiteBox.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test WhiteBox
+ * @bug 8011675
+ * @summary verify that whitebox can be used even if not all functions are declared in java-part
+ * @author igor.ignatyev@oracle.com
+ * @library /testlibrary
+ * @compile WhiteBox.java
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox
+ * @clean sun.hotspot.WhiteBox
+ */
+
+package sun.hotspot;
+
+public class WhiteBox {
+    private static native void registerNatives();
+    static { registerNatives(); }
+    public native int notExistedMethod();
+    public native int getHeapOopSize();
+    public static void main(String[] args) {
+        WhiteBox wb = new WhiteBox();
+        if (wb.getHeapOopSize() < 0) {
+            throw new Error("wb.getHeapOopSize() < 0");
+        }
+        boolean catched = false;
+        try {
+            wb.notExistedMethod();
+        } catch (UnsatisfiedLinkError e) {
+            catched = true;
+        }
+        if (!catched) {
+            throw new Error("wb.notExistedMethod() was invoked");
+        }
+    }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Wed May 08 11:22:25 2013 +0100
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java	Thu May 16 11:47:51 2013 +0100
@@ -61,6 +61,9 @@
     registerNatives();
   }
 
+  // Arguments
+  public native void printHeapSizes();
+
   // Memory
   public native long getObjectAddress(Object o);
   public native int  getHeapOopSize();
@@ -111,6 +114,9 @@
   // Intered strings
   public native boolean isInStringTable(String str);
 
+  // Memory
+  public native long reserveMemory(long size);
+
   // force Full GC
   public native void fullGC();
 }
--- a/jaxp/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 41b50e2c5ea3f4aa1af729e1deb1678cb3e1ef9c jdk8-b85
 ca71ec37b2efc9c3f0971ebabb3a6eb1213d76de jdk8-b86
 eddbc8ad2435a89f64729512337c9f2669e4dd85 jdk8-b87
+7122f7bb0fcc8a39e5254402119b2ee3fa0ad313 jdk8-b88
+893d2ba8bbea3a8d090e51d8eaea285b390789ea jdk8-b89
--- a/jaxp/build.xml	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/build.xml	Thu May 16 11:47:51 2013 +0100
@@ -176,4 +176,42 @@
         <echo message="+---------------------------------------+"/>
     </target>
 
+    <target name="javadoc" depends="init" description="Build basic Javadoc for public packages.">
+        <property name="javadoc.options" value=""/> <!-- default, can be overridden per user or per project -->
+        <!-- Note: even with this default value, includes/excludes
+         from share.src.dir get javadoc'd; see packageset below -->
+        <property name="javadoc.packagenames" value="none"/> <!-- default, can be overridden per user or per project -->
+        <property name="javadoc.dir" value="${build.dir}/docs/api"/>
+        <property name="includes" value="**"/>
+        <javadoc destdir="${javadoc.dir}" source="1.5"
+            windowtitle="UNOFFICIAL" failonerror="true" use="true"
+            author="false" version="false"
+            packagenames="${javadoc.packagenames}">
+            <header><![CDATA[<strong>Unofficial Javadoc</strong> generated from developer sources for preview purposes only]]></header>
+            <arg line="${javadoc.options}"/>
+            <bootclasspath>
+                <path location="${java.home}/lib/rt.jar"/>
+                <path location="${build.classes.dir}"/>
+            </bootclasspath>
+            <sourcepath>
+                <pathelement location="${jaxp.src.dir}"/>
+            </sourcepath>
+            <!-- XXX just <fileset> (restricted further to **/*.java) and no <packageset> -->
+            <!-- means that {@link some.package} will not work, which is no good. -->
+            <!-- (It correctly skips excluded single classes, but not if packageset is also included, -->
+            <!-- which also causes duplicates in the class index for included files.) -->
+            <packageset dir="${jaxp.src.dir}" includes="${includes}" excludes="${excludes}">
+                <or>
+                    <filename name="javax/"/>
+                    <filename name="org/w3c/"/>
+                    <filename name="org/xml/sax/"/>
+                </or>
+            </packageset>
+        </javadoc>
+    </target>
+    <target name="javadoc-nb" depends="javadoc" if="netbeans.home">
+        <property name="javadoc.dir=" value="${build.dir}/docs/api"/>
+        <nbbrowse file="${javadoc.dir}/index.html"/>
+    </target>
+
 </project>
--- a/jaxp/nbproject/project.xml	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/nbproject/project.xml	Thu May 16 11:47:51 2013 +0100
@@ -15,6 +15,12 @@
                     <location>.</location>
                     <encoding>UTF-8</encoding>
                 </source-folder>
+                <source-folder>
+                    <label>src</label>
+                    <type>java</type>
+                    <location>src</location>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
             </folders>
             <ide-actions>
                 <action name="build">
@@ -27,9 +33,16 @@
                     <target>clean</target>
                     <target>build</target>
                 </action>
+                <action name="javadoc">
+                    <target>javadoc-nb</target>
+                </action>
             </ide-actions>
             <view>
                 <items>
+                    <source-folder style="packages">
+                        <label>src</label>
+                        <location>src</location>
+                    </source-folder>
                     <source-file>
                         <location>build.xml</location>
                     </source-file>
@@ -38,11 +51,16 @@
                     <ide-action name="build"/>
                     <ide-action name="rebuild"/>
                     <ide-action name="clean"/>
+                    <ide-action name="javadoc"/>
                 </context-menu>
             </view>
             <subprojects/>
         </general-data>
-        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/1"/>
+        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/1">
+            <compilation-unit>
+                <package-root>src</package-root>
+            </compilation-unit>
+        </java-data>
         <preferences xmlns="http://www.netbeans.org/ns/auxiliary-configuration-preferences/1">
             <module name="org-netbeans-modules-editor-indent"/>
         </preferences>
--- a/jaxp/src/javax/xml/datatype/DatatypeFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/datatype/DatatypeFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,8 @@
 
 package javax.xml.datatype;
 
+import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.math.BigDecimal;
 import java.util.GregorianCalendar;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -34,12 +34,12 @@
 /**
  * <p>Factory that creates new <code>javax.xml.datatype</code> <code>Object</code>s that map XML to/from Java <code>Object</code>s.</p>
  *
- * <p><a name="DatatypeFactory.newInstance"/>{@link #newInstance()} is used to create a new <code>DatatypeFactory</code>.
- * The following implementation resolution mechanisms are used in the following order:</p>
+ * <p>A new instance of the <code>DatatypeFactory</code> is created through the {@link #newInstance()} method
+ * that uses the following implementation resolution mechanisms to determine an implementation:</p>
  * <ol>
  *    <li>
  *      If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "<code>javax.xml.datatype.DatatypeFactory</code>",
- *      exists, a class with the name of the property's value is instantiated.
+ *      exists, a class with the name of the property value is instantiated.
  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
  *    </li>
  *    <li>
@@ -48,8 +48,12 @@
  *      and processed as documented in the prior step.
  *    </li>
  *    <li>
- *      The services resolution mechanism is used, e.g. <code>META-INF/services/java.xml.datatype.DatatypeFactory</code>.
- *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
+ *     Uses the service-provider loading facilities, defined by the {@link java.util.ServiceLoader} class, to attempt
+ *     to locate and load an implementation of the service.
+ *     <br>
+ *     In case of {@link java.util.ServiceConfigurationError service
+ *     configuration error} a {@link javax.xml.datatype.DatatypeConfigurationException}
+ *     will be thrown.
  *    </li>
  *    <li>
  *      The final mechanism is to attempt to instantiate the <code>Class</code> specified by
@@ -67,26 +71,33 @@
  */
 public abstract class DatatypeFactory {
 
-        /**
-         * <p>Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
-         *
-         * <p>Default value is <code>javax.xml.datatype.DatatypeFactory</code>.</p>
-         */
-        public static final String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory";
+    /**
+     * <p>Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
+     *
+     * <p>Default value is <code>javax.xml.datatype.DatatypeFactory</code>.</p>
+     */
+    public static final String DATATYPEFACTORY_PROPERTY =
+            // We use a String constant here, rather than calling
+            // DatatypeFactory.class.getName() - in order to make javadoc
+            // generate a See Also: Constant Field Value link.
+            "javax.xml.datatype.DatatypeFactory";
 
-        /**
-         * <p>Default implementation class name as defined in
-         * <em>JSR 206: Java(TM) API for XML Processing (JAXP) 1.3</em>.</p>
-         *
-         * <p>Implementers should specify the name of an appropriate class
-         * to be instantiated if no other implementation resolution mechanism
-         * succeeds.</p>
-         *
-         * <p>Users should not refer to this field; it is intended only to
-         * document a factory implementation detail.
-         * </p>
-         */
-        public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl");
+    /**
+     * <p>Default implementation class name as defined in
+     * <em>JSR 206: Java(TM) API for XML Processing (JAXP) 1.3</em>.</p>
+     *
+     * <p>Implementers should specify the name of an appropriate class
+     * to be instantiated if no other implementation resolution mechanism
+     * succeeds.</p>
+     *
+     * <p>Users should not refer to this field; it is intended only to
+     * document a factory implementation detail.
+     * </p>
+     */
+    public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS =
+        // We use new String() here to prevent javadoc from generating
+        // a See Also: Constant Field Value link.
+        new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl");
 
     /**
      * http://www.w3.org/TR/xpath-datamodel/#xdtschema defines two regexps
@@ -101,40 +112,36 @@
     private static final Pattern XDTSCHEMA_DTD =
         Pattern.compile("[^YM]*[DT].*");
 
-        /**
-         * <p>Protected constructor to prevent instaniation outside of package.</p>
-         *
-         * <p>Use {@link #newInstance()} to create a <code>DatatypeFactory</code>.</p>
-         */
-        protected DatatypeFactory() {
-        }
+    /**
+     * <p>Protected constructor to prevent instaniation outside of package.</p>
+     *
+     * <p>Use {@link #newInstance()} to create a <code>DatatypeFactory</code>.</p>
+     */
+    protected DatatypeFactory() {
+    }
 
-        /**
-         * <p>Obtain a new instance of a <code>DatatypeFactory</code>.</p>
-         *
+    /**
+     * <p>Obtain a new instance of a <code>DatatypeFactory</code>.</p>
+     *
      * <p>The implementation resolution mechanisms are <a href="#DatatypeFactory.newInstance">defined</a> in this
      * <code>Class</code>'s documentation.</p>
-         *
-         * @return New instance of a <code>DatatypeFactory</code>
-         *
-         * @throws DatatypeConfigurationException If the implementation is not
-         *   available or cannot be instantiated.
+     *
+     * @return New instance of a <code>DatatypeFactory</code>
+     *
+     * @throws DatatypeConfigurationException If the implementation is not
+     *   available or cannot be instantiated.
      *
      * @see #newInstance(String factoryClassName, ClassLoader classLoader)
-         */
-        public static DatatypeFactory newInstance()
-                throws DatatypeConfigurationException {
+     */
+    public static DatatypeFactory newInstance()
+            throws DatatypeConfigurationException {
 
-                try {
-                        return (DatatypeFactory) FactoryFinder.find(
-                                /* The default property name according to the JAXP spec */
-                                 DATATYPEFACTORY_PROPERTY,
-                                /* The fallback implementation class name */
-                                DATATYPEFACTORY_IMPLEMENTATION_CLASS);
-                } catch (FactoryFinder.ConfigurationError e) {
-                        throw new DatatypeConfigurationException(e.getMessage(), e.getException());
-                }
-        }
+            return FactoryFinder.find(
+                    /* The default property name according to the JAXP spec */
+                    DatatypeFactory.class,
+                    /* The fallback implementation class name */
+                    DATATYPEFACTORY_IMPLEMENTATION_CLASS);
+    }
 
     /**
      * <p>Obtain a new instance of a <code>DatatypeFactory</code> from class name.
@@ -172,57 +179,54 @@
      */
     public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader)
         throws DatatypeConfigurationException {
-        try {
-            return (DatatypeFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false);
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new DatatypeConfigurationException(e.getMessage(), e.getException());
-        }
-    }
+        return FactoryFinder.newInstance(DatatypeFactory.class,
+                    factoryClassName, classLoader, false);
+     }
 
-        /**
-         * <p>Obtain a new instance of a <code>Duration</code>
-         * specifying the <code>Duration</code> as its string representation, "PnYnMnDTnHnMnS",
-         * as defined in XML Schema 1.0 section 3.2.6.1.</p>
-         *
-         * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
-         * <blockquote>
-         * duration represents a duration of time.
-         * The value space of duration is a six-dimensional space where the coordinates designate the
-         * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
-         * These components are ordered in their significance by their order of appearance i.e. as
-         * year, month, day, hour, minute, and second.
-         * </blockquote>
-     * <p>All six values are set and availabe from the created {@link Duration}</p>
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as its string representation, "PnYnMnDTnHnMnS",
+     * as defined in XML Schema 1.0 section 3.2.6.1.</p>
+     *
+     * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
+     * <blockquote>
+     * duration represents a duration of time.
+     * The value space of duration is a six-dimensional space where the coordinates designate the
+     * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
+     * These components are ordered in their significance by their order of appearance i.e. as
+     * year, month, day, hour, minute, and second.
+     * </blockquote>
+     * <p>All six values are set and available from the created {@link Duration}</p>
      *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
      * if implementation capacities are exceeded.</p>
-         *
-         * @param lexicalRepresentation <code>String</code> representation of a <code>Duration</code>.
-         *
-         * @return New <code>Duration</code> created from parsing the <code>lexicalRepresentation</code>.
-         *
-         * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code>.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         * @throws NullPointerException if <code>lexicalRepresentation</code> is <code>null</code>.
-         */
-        public abstract Duration newDuration(final String lexicalRepresentation);
+     *
+     * @param lexicalRepresentation <code>String</code> representation of a <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created from parsing the <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code>.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException if <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public abstract Duration newDuration(final String lexicalRepresentation);
 
-        /**
-         * <p>Obtain a new instance of a <code>Duration</code>
-         * specifying the <code>Duration</code> as milliseconds.</p>
-         *
-         * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
-         * <blockquote>
-         * duration represents a duration of time.
-         * The value space of duration is a six-dimensional space where the coordinates designate the
-         * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
-         * These components are ordered in their significance by their order of appearance i.e. as
-         * year, month, day, hour, minute, and second.
-         * </blockquote>
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as milliseconds.</p>
+     *
+     * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
+     * <blockquote>
+     * duration represents a duration of time.
+     * The value space of duration is a six-dimensional space where the coordinates designate the
+     * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
+     * These components are ordered in their significance by their order of appearance i.e. as
+     * year, month, day, hour, minute, and second.
+     * </blockquote>
      * <p>All six values are set by computing their values from the specified milliseconds
-     * and are availabe using the <code>get</code> methods of  the created {@link Duration}.
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
      * The values conform to and are defined by:</p>
      * <ul>
      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
@@ -231,25 +235,25 @@
      *   </li>
      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
      * </ul>
-         *
-         * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
-         * {@link java.util.Calendar#YEAR} = 1970,
-         * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
-         * {@link java.util.Calendar#DATE} = 1, etc.
-         * This is important as there are variations in the Gregorian Calendar,
-         * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
-         * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.</p>
-         *
-         * @param durationInMilliSeconds Duration in milliseconds to create.
-         *
-         * @return New <code>Duration</code> representing <code>durationInMilliSeconds</code>.
-         */
-        public abstract Duration newDuration(final long durationInMilliSeconds);
+     *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.</p>
+     *
+     * @param durationInMilliSeconds Duration in milliseconds to create.
+     *
+     * @return New <code>Duration</code> representing <code>durationInMilliSeconds</code>.
+     */
+    public abstract Duration newDuration(final long durationInMilliSeconds);
 
-        /**
-         * <p>Obtain a new instance of a <code>Duration</code>
-         * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
-         *
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
+     *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
@@ -257,35 +261,35 @@
      *
      * <p>A <code>null</code> value indicates that field is not set.</p>
      *
-         * @param isPositive Set to <code>false</code> to create a negative duration. When the length
-         *   of the duration is zero, this parameter will be ignored.
-         * @param years of this <code>Duration</code>
-         * @param months of this <code>Duration</code>
-         * @param days of this <code>Duration</code>
-         * @param hours of this <code>Duration</code>
-         * @param minutes of this <code>Duration</code>
-         * @param seconds of this <code>Duration</code>
-         *
-         * @return New <code>Duration</code> created from the specified values.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if all the fields (years, months, ...) are null or
-         * if any of the fields is negative.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         */
-        public abstract Duration newDuration(
-                final boolean isPositive,
-                final BigInteger years,
-                final BigInteger months,
-                final BigInteger days,
-                final BigInteger hours,
-                final BigInteger minutes,
-                final BigDecimal seconds);
+     * @param isPositive Set to <code>false</code> to create a negative duration. When the length
+     *   of the duration is zero, this parameter will be ignored.
+     * @param years of this <code>Duration</code>
+     * @param months of this <code>Duration</code>
+     * @param days of this <code>Duration</code>
+     * @param hours of this <code>Duration</code>
+     * @param minutes of this <code>Duration</code>
+     * @param seconds of this <code>Duration</code>
+     *
+     * @return New <code>Duration</code> created from the specified values.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if all the fields (years, months, ...) are null or
+     * if any of the fields is negative.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public abstract Duration newDuration(
+            final boolean isPositive,
+            final BigInteger years,
+            final BigInteger months,
+            final BigInteger days,
+            final BigInteger hours,
+            final BigInteger minutes,
+            final BigDecimal seconds);
 
-        /**
-         * <p>Obtain a new instance of a <code>Duration</code>
-         * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
-         *
+    /**
+     * <p>Obtain a new instance of a <code>Duration</code>
+     * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
@@ -297,113 +301,113 @@
      * @param minutes of this <code>Duration</code>
      * @param seconds of this <code>Duration</code>
      *
-         * @return New <code>Duration</code> created from the specified values.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if any of the fields is negative.
-         *
-         * @see #newDuration(
-         *   boolean isPositive,
-         *   BigInteger years,
-         *   BigInteger months,
-         *   BigInteger days,
-         *   BigInteger hours,
-         *   BigInteger minutes,
-         *   BigDecimal seconds)
-         */
-        public Duration newDuration(
-                final boolean isPositive,
-                final int years,
-                final int months,
-                final int days,
-                final int hours,
-                final int minutes,
-                final int seconds) {
+     * @return New <code>Duration</code> created from the specified values.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if any of the fields is negative.
+     *
+     * @see #newDuration(
+     *   boolean isPositive,
+     *   BigInteger years,
+     *   BigInteger months,
+     *   BigInteger days,
+     *   BigInteger hours,
+     *   BigInteger minutes,
+     *   BigDecimal seconds)
+     */
+    public Duration newDuration(
+            final boolean isPositive,
+            final int years,
+            final int months,
+            final int days,
+            final int hours,
+            final int minutes,
+            final int seconds) {
 
-                // years may not be set
-                BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null;
+            // years may not be set
+            BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null;
 
-                // months may not be set
-                BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null;
+            // months may not be set
+            BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null;
 
-                // days may not be set
-                BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null;
+            // days may not be set
+            BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null;
 
-                // hours may not be set
-                BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null;
+            // hours may not be set
+            BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null;
 
-                // minutes may not be set
-                BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null;
+            // minutes may not be set
+            BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null;
 
-                // seconds may not be set
-                BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null;
+            // seconds may not be set
+            BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null;
 
-                        return newDuration(
-                                isPositive,
-                                realYears,
-                                realMonths,
-                                realDays,
-                                realHours,
-                                realMinutes,
-                                realSeconds
-                        );
-                }
+                    return newDuration(
+                            isPositive,
+                            realYears,
+                            realMonths,
+                            realDays,
+                            realHours,
+                            realMinutes,
+                            realSeconds
+                    );
+            }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> by parsing its <code>String</code> representation,
-         * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only day, hour, minute, and second components.
-         * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
-         *
-     * <p>All four values are set and availabe from the created {@link Duration}</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> by parsing its <code>String</code> representation,
+     * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
+     * <p>All four values are set and available from the created {@link Duration}</p>
+     *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
      * if implementation capacities are exceeded.</p>
      *
-         * @param lexicalRepresentation Lexical representation of a duration.
-         *
-         * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
-         *
-         * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of days and time.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
-         */
-        public Duration newDurationDayTime(final String lexicalRepresentation) {
-            // lexicalRepresentation must be non-null
-            if (lexicalRepresentation == null) {
-                throw new NullPointerException(
-                    "Trying to create an xdt:dayTimeDuration with an invalid"
-                    + " lexical representation of \"null\"");
-            }
-
-            // test lexicalRepresentation against spec regex
-            Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation);
-            if (!matcher.matches()) {
-                throw new IllegalArgumentException(
-                    "Trying to create an xdt:dayTimeDuration with an invalid"
-                    + " lexical representation of \"" + lexicalRepresentation
-                    + "\", data model requires years and months only.");
-            }
-
-            return newDuration(lexicalRepresentation);
+     * @param lexicalRepresentation Lexical representation of a duration.
+     *
+     * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of days and time.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public Duration newDurationDayTime(final String lexicalRepresentation) {
+        // lexicalRepresentation must be non-null
+        if (lexicalRepresentation == null) {
+            throw new NullPointerException(
+                "Trying to create an xdt:dayTimeDuration with an invalid"
+                + " lexical representation of \"null\"");
         }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified milliseconds as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only day, hour, minute, and second components.
-         * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
-         *
+        // test lexicalRepresentation against spec regex
+        Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation);
+        if (!matcher.matches()) {
+            throw new IllegalArgumentException(
+                "Trying to create an xdt:dayTimeDuration with an invalid"
+                + " lexical representation of \"" + lexicalRepresentation
+                + "\", data model requires years and months only.");
+        }
+
+        return newDuration(lexicalRepresentation);
+    }
+
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified milliseconds as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
      * <p>All four values are set by computing their values from the specified milliseconds
-     * and are availabe using the <code>get</code> methods of  the created {@link Duration}.
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
      * The values conform to and are defined by:</p>
      * <ul>
      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
@@ -412,39 +416,39 @@
      *   </li>
      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
      * </ul>
-         *
-         * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
-         * {@link java.util.Calendar#YEAR} = 1970,
-         * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
-         * {@link java.util.Calendar#DATE} = 1, etc.
-         * This is important as there are variations in the Gregorian Calendar,
-         * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
-         * so the result of {@link Duration#getDays()} can be influenced.</p>
-         *
+     *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getDays()} can be influenced.</p>
+     *
      * <p>Any remaining milliseconds after determining the day, hour, minute and second are discarded.</p>
      *
-         * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
-         *
-         * @return New <code>Duration</code> created with the specified <code>durationInMilliseconds</code>.
-         *
-         * @see <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>
-         */
-        public Duration newDurationDayTime(final long durationInMilliseconds) {
+     * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
+     *
+     * @return New <code>Duration</code> created with the specified <code>durationInMilliseconds</code>.
+     *
+     * @see <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>
+     */
+    public Duration newDurationDayTime(final long durationInMilliseconds) {
 
-                return newDuration(durationInMilliseconds);
-        }
+            return newDuration(durationInMilliseconds);
+    }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
-         * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only day, hour, minute, and second components.
-         * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
+     * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
@@ -454,102 +458,102 @@
      *
      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
      *   of the duration is zero, this parameter will be ignored.
-         * @param day Day of <code>Duration</code>.
-         * @param hour Hour of <code>Duration</code>.
-         * @param minute Minute of <code>Duration</code>.
-         * @param second Second of <code>Duration</code>.
-         *
-         * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
-         * and <code>second</code>.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if all the fields (day, hour, ...) are null or
-         * if any of the fields is negative.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         */
-        public Duration newDurationDayTime(
-                final boolean isPositive,
-                final BigInteger day,
-                final BigInteger hour,
-                final BigInteger minute,
-                final BigInteger second) {
+     * @param day Day of <code>Duration</code>.
+     * @param hour Hour of <code>Duration</code>.
+     * @param minute Minute of <code>Duration</code>.
+     * @param second Second of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
+     * and <code>second</code>.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if all the fields (day, hour, ...) are null or
+     * if any of the fields is negative.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public Duration newDurationDayTime(
+            final boolean isPositive,
+            final BigInteger day,
+            final BigInteger hour,
+            final BigInteger minute,
+            final BigInteger second) {
 
-                return newDuration(
-                        isPositive,
-                        null,  // years
-                        null, // months
-                        day,
-                        hour,
-                        minute,
-                        (second != null)? new BigDecimal(second):null
-                );
-        }
+            return newDuration(
+                    isPositive,
+                    null,  // years
+                    null, // months
+                    day,
+                    hour,
+                    minute,
+                    (second != null)? new BigDecimal(second):null
+            );
+    }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
-         * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only day, hour, minute, and second components.
-         * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
+     * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only day, hour, minute, and second components.
+     * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
      *   of the duration is zero, this parameter will be ignored.
-         * @param day Day of <code>Duration</code>.
-         * @param hour Hour of <code>Duration</code>.
-         * @param minute Minute of <code>Duration</code>.
-         * @param second Second of <code>Duration</code>.
-         *
-         * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
-         * and <code>second</code>.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if any of the fields (day, hour, ...) is negative.
-         */
-        public Duration newDurationDayTime(
-                final boolean isPositive,
-                final int day,
-                final int hour,
-                final int minute,
-                final int second) {
+     * @param day Day of <code>Duration</code>.
+     * @param hour Hour of <code>Duration</code>.
+     * @param minute Minute of <code>Duration</code>.
+     * @param second Second of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
+     * and <code>second</code>.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if any of the fields (day, hour, ...) is negative.
+     */
+    public Duration newDurationDayTime(
+            final boolean isPositive,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second) {
 
-                        return newDurationDayTime(
-                                isPositive,
-                                BigInteger.valueOf((long) day),
-                                BigInteger.valueOf((long) hour),
-                                BigInteger.valueOf((long) minute),
-                                BigInteger.valueOf((long) second)
-                                );
-                }
+                    return newDurationDayTime(
+                            isPositive,
+                            BigInteger.valueOf((long) day),
+                            BigInteger.valueOf((long) hour),
+                            BigInteger.valueOf((long) minute),
+                            BigInteger.valueOf((long) second)
+                            );
+            }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
-         * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only year and month components.
-         * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
-         *
-     * <p>Both values are set and availabe from the created {@link Duration}</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
+     * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only year and month components.
+     * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
+     *
+     * <p>Both values are set and available from the created {@link Duration}</p>
+     *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
      * if implementation capacities are exceeded.</p>
      *
-         * @param lexicalRepresentation Lexical representation of a duration.
-         *
-         * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
-         *
-         * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of years and months.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
-         */
+     * @param lexicalRepresentation Lexical representation of a duration.
+     *
+     * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of years and months.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
     public Duration newDurationYearMonth(
             final String lexicalRepresentation) {
 
@@ -572,17 +576,17 @@
         return newDuration(lexicalRepresentation);
     }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
-         *
-         * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
-         * whose lexical representation contains only year and month components.
-         * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
+     * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
+     * whose lexical representation contains only year and month components.
+     * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
+     *
      * <p>Both values are set by computing their values from the specified milliseconds
-     * and are availabe using the <code>get</code> methods of  the created {@link Duration}.
+     * and are available using the <code>get</code> methods of  the created {@link Duration}.
      * The values conform to and are defined by:</p>
      * <ul>
      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
@@ -592,20 +596,20 @@
      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
      * </ul>
      *
-         * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
-         * {@link java.util.Calendar#YEAR} = 1970,
-         * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
-         * {@link java.util.Calendar#DATE} = 1, etc.
-         * This is important as there are variations in the Gregorian Calendar,
-         * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
-         * so the result of {@link Duration#getMonths()} can be influenced.</p>
-         *
+     * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
+     * {@link java.util.Calendar#YEAR} = 1970,
+     * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
+     * {@link java.util.Calendar#DATE} = 1, etc.
+     * This is important as there are variations in the Gregorian Calendar,
+     * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
+     * so the result of {@link Duration#getMonths()} can be influenced.</p>
+     *
      * <p>Any remaining milliseconds after determining the year and month are discarded.</p>
-         *
-         * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
-         *
-         * @return New <code>Duration</code> created using the specified <code>durationInMilliseconds</code>.
-         */
+     *
+     * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
+     *
+     * @return New <code>Duration</code> created using the specified <code>durationInMilliseconds</code>.
+     */
     public Duration newDurationYearMonth(
             final long durationInMilliseconds) {
 
@@ -624,12 +628,12 @@
         return newDurationYearMonth(isPositive, years, months);
     }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
-         * <code>year</code> and <code>month</code> as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
+     * <code>year</code> and <code>month</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
      * <p>The XML Schema specification states that values can be of an arbitrary size.
      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
@@ -639,74 +643,74 @@
      *
      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
      *   of the duration is zero, this parameter will be ignored.
-         * @param year Year of <code>Duration</code>.
-         * @param month Month of <code>Duration</code>.
-         *
-         * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if all of the fields (year, month) are null or
-         * if any of the fields is negative.
-         * @throws UnsupportedOperationException If implementation cannot support requested values.
-         */
-        public Duration newDurationYearMonth(
-                final boolean isPositive,
-                final BigInteger year,
-                final BigInteger month) {
+     * @param year Year of <code>Duration</code>.
+     * @param month Month of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if all of the fields (year, month) are null or
+     * if any of the fields is negative.
+     * @throws UnsupportedOperationException If implementation cannot support requested values.
+     */
+    public Duration newDurationYearMonth(
+            final boolean isPositive,
+            final BigInteger year,
+            final BigInteger month) {
 
-                return newDuration(
-                        isPositive,
-                        year,
-                        month,
-                        null, // days
-                        null, // hours
-                        null, // minutes
-                        null  // seconds
-                );
-        }
+            return newDuration(
+                    isPositive,
+                    year,
+                    month,
+                    null, // days
+                    null, // hours
+                    null, // minutes
+                    null  // seconds
+            );
+    }
 
-        /**
-         * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
-         * <code>year</code> and <code>month</code> as defined in
-         * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
-         *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
-         *
+    /**
+     * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
+     * <code>year</code> and <code>month</code> as defined in
+     * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
+     *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
      *   of the duration is zero, this parameter will be ignored.
-         * @param year Year of <code>Duration</code>.
-         * @param month Month of <code>Duration</code>.
-         *
-         * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
-         *
-         * @throws IllegalArgumentException If the values are not a valid representation of a
-         * <code>Duration</code>: if any of the fields (year, month) is negative.
-         */
-        public Duration newDurationYearMonth(
-                final boolean isPositive,
-                final int year,
-                final int month) {
+     * @param year Year of <code>Duration</code>.
+     * @param month Month of <code>Duration</code>.
+     *
+     * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
+     *
+     * @throws IllegalArgumentException If the values are not a valid representation of a
+     * <code>Duration</code>: if any of the fields (year, month) is negative.
+     */
+    public Duration newDurationYearMonth(
+            final boolean isPositive,
+            final int year,
+            final int month) {
 
-                return newDurationYearMonth(
-                        isPositive,
-                        BigInteger.valueOf((long) year),
-                        BigInteger.valueOf((long) month));
-                }
+            return newDurationYearMonth(
+                    isPositive,
+                    BigInteger.valueOf((long) year),
+                    BigInteger.valueOf((long) month));
+            }
 
-        /**
-         * <p>Create a new instance of an <code>XMLGregorianCalendar</code>.</p>
-         *
+    /**
+     * <p>Create a new instance of an <code>XMLGregorianCalendar</code>.</p>
+     *
      * <p>All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.</p>
      *
      * @return New <code>XMLGregorianCalendar</code> with all date/time datatype fields set to
      *   {@link DatatypeConstants#FIELD_UNDEFINED} or null.
-         */
-        public abstract XMLGregorianCalendar newXMLGregorianCalendar();
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar();
 
-        /**
-         * <p>Create a new XMLGregorianCalendar by parsing the String as a lexical representation.</p>
-         *
+    /**
+     * <p>Create a new XMLGregorianCalendar by parsing the String as a lexical representation.</p>
+     *
      * <p>Parsing the lexical string representation is defined in
      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
      * <em>Lexical Representation</em>.</a></p>
@@ -721,344 +725,344 @@
      * <p>Except for the noted lexical/canonical representation mismatches
      * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
      * XML Schema 1.0 errata, Section 3.2.7.2</a>.</p>
-         *
-         * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from the <code>lexicalRepresentation</code>.
-         *
-         * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> is not a valid <code>XMLGregorianCalendar</code>.
-         * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
-         */
-        public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation);
+     *
+     * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from the <code>lexicalRepresentation</code>.
+     *
+     * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> is not a valid <code>XMLGregorianCalendar</code>.
+     * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation);
 
-        /**
-         * <p>Create an <code>XMLGregorianCalendar</code> from a {@link GregorianCalendar}.</p>
-         *
-         * <table border="2" rules="all" cellpadding="2">
-         *   <thead>
-         *     <tr>
-         *       <th align="center" colspan="2">
-         *          Field by Field Conversion from
-         *          {@link GregorianCalendar} to an {@link XMLGregorianCalendar}
-         *       </th>
-         *     </tr>
-         *     <tr>
-         *        <th><code>java.util.GregorianCalendar</code> field</th>
-         *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
-         *     </tr>
-         *   </thead>
-         *   <tbody>
-         *     <tr>
-         *       <td><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></td>
-         *       <td>{@link XMLGregorianCalendar#setYear(int year)}</td>
-         *     </tr>
-         *     <tr>
-         *       <td><code>MONTH + 1</code></td>
-         *       <td>{@link XMLGregorianCalendar#setMonth(int month)}</td>
-         *     </tr>
-         *     <tr>
-         *       <td><code>DAY_OF_MONTH</code></td>
-         *       <td>{@link XMLGregorianCalendar#setDay(int day)}</td>
-         *     </tr>
-         *     <tr>
-         *       <td><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></td>
-         *       <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td>
-         *     </tr>
-         *     <tr>
-         *       <td>
-         *         <code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
-         *         <em>(in minutes)</em>
-         *       </td>
-         *       <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup>
-         *       </td>
-         *     </tr>
-         *   </tbody>
-         * </table>
-         * <p><em>*</em>conversion loss of information. It is not possible to represent
-         * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
-         * XML Schema 1.0 date/time datatype representation.</p>
-         *
-         * <p>To compute the return value's <code>TimeZone</code> field,
-         * <ul>
-         * <li>when <code>this.getTimezone() != FIELD_UNDEFINED</code>,
-         * create a <code>java.util.TimeZone</code> with a custom timezone id
-         * using the <code>this.getTimezone()</code>.</li>
-         * <li>else use the <code>GregorianCalendar</code> default timezone value
-         * for the host is defined as specified by
-         * <code>java.util.TimeZone.getDefault()</code>.</li></p>
-         *
-         * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
-         *
-         * @return <code>XMLGregorianCalendar</code> created from <code>java.util.GregorianCalendar</code>
-         *
-         * @throws NullPointerException If <code>cal</code> is <code>null</code>.
-         */
-        public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal);
+    /**
+     * <p>Create an <code>XMLGregorianCalendar</code> from a {@link GregorianCalendar}.</p>
+     *
+     * <table border="2" rules="all" cellpadding="2">
+     *   <thead>
+     *     <tr>
+     *       <th align="center" colspan="2">
+     *          Field by Field Conversion from
+     *          {@link GregorianCalendar} to an {@link XMLGregorianCalendar}
+     *       </th>
+     *     </tr>
+     *     <tr>
+     *        <th><code>java.util.GregorianCalendar</code> field</th>
+     *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
+     *     </tr>
+     *   </thead>
+     *   <tbody>
+     *     <tr>
+     *       <td><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></td>
+     *       <td>{@link XMLGregorianCalendar#setYear(int year)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>MONTH + 1</code></td>
+     *       <td>{@link XMLGregorianCalendar#setMonth(int month)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>DAY_OF_MONTH</code></td>
+     *       <td>{@link XMLGregorianCalendar#setDay(int day)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></td>
+     *       <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td>
+     *     </tr>
+     *     <tr>
+     *       <td>
+     *         <code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
+     *         <em>(in minutes)</em>
+     *       </td>
+     *       <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup>
+     *       </td>
+     *     </tr>
+     *   </tbody>
+     * </table>
+     * <p><em>*</em>conversion loss of information. It is not possible to represent
+     * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
+     * XML Schema 1.0 date/time datatype representation.</p>
+     *
+     * <p>To compute the return value's <code>TimeZone</code> field,
+     * <ul>
+     * <li>when <code>this.getTimezone() != FIELD_UNDEFINED</code>,
+     * create a <code>java.util.TimeZone</code> with a custom timezone id
+     * using the <code>this.getTimezone()</code>.</li>
+     * <li>else use the <code>GregorianCalendar</code> default timezone value
+     * for the host is defined as specified by
+     * <code>java.util.TimeZone.getDefault()</code>.</li></p>
+     *
+     * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
+     *
+     * @return <code>XMLGregorianCalendar</code> created from <code>java.util.GregorianCalendar</code>
+     *
+     * @throws NullPointerException If <code>cal</code> is <code>null</code>.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal);
 
-        /**
-         * <p>Constructor allowing for complete value spaces allowed by
-         * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
-         * builtin datatypes. Note that <code>year</code> parameter supports
-         * arbitrarily large numbers and fractionalSecond has infinite
-         * precision.</p>
-         *
+    /**
+     * <p>Constructor allowing for complete value spaces allowed by
+     * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
+     * builtin datatypes. Note that <code>year</code> parameter supports
+     * arbitrarily large numbers and fractionalSecond has infinite
+     * precision.</p>
+     *
      * <p>A <code>null</code> value indicates that field is not set.</p>
      *
-         * @param year of <code>XMLGregorianCalendar</code> to be created.
-         * @param month of <code>XMLGregorianCalendar</code> to be created.
-         * @param day of <code>XMLGregorianCalendar</code> to be created.
-         * @param hour of <code>XMLGregorianCalendar</code> to be created.
-         * @param minute of <code>XMLGregorianCalendar</code> to be created.
-         * @param second of <code>XMLGregorianCalendar</code> to be created.
-         * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
-         * @param timezone of <code>XMLGregorianCalendar</code> to be created.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from specified values.
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         */
-        public abstract XMLGregorianCalendar newXMLGregorianCalendar(
-                final BigInteger year,
-                final int month,
-                final int day,
-                final int hour,
-                final int minute,
-                final int second,
-                final BigDecimal fractionalSecond,
-                final int timezone);
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param hour of <code>XMLGregorianCalendar</code> to be created.
+     * @param minute of <code>XMLGregorianCalendar</code> to be created.
+     * @param second of <code>XMLGregorianCalendar</code> to be created.
+     * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from specified values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public abstract XMLGregorianCalendar newXMLGregorianCalendar(
+            final BigInteger year,
+            final int month,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second,
+            final BigDecimal fractionalSecond,
+            final int timezone);
 
-        /**
-         * <p>Constructor of value spaces that a
-         * <code>java.util.GregorianCalendar</code> instance would need to convert to an
-         * <code>XMLGregorianCalendar</code> instance.</p>
-         *
-         * <p><code>XMLGregorianCalendar eon</code> and
-         * <code>fractionalSecond</code> are set to <code>null</code></p>
-         *
+    /**
+     * <p>Constructor of value spaces that a
+     * <code>java.util.GregorianCalendar</code> instance would need to convert to an
+     * <code>XMLGregorianCalendar</code> instance.</p>
+     *
+     * <p><code>XMLGregorianCalendar eon</code> and
+     * <code>fractionalSecond</code> are set to <code>null</code></p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
-         * @param year of <code>XMLGregorianCalendar</code> to be created.
-         * @param month of <code>XMLGregorianCalendar</code> to be created.
-         * @param day of <code>XMLGregorianCalendar</code> to be created.
-         * @param hour of <code>XMLGregorianCalendar</code> to be created.
-         * @param minute of <code>XMLGregorianCalendar</code> to be created.
-         * @param second of <code>XMLGregorianCalendar</code> to be created.
-         * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
-         * @param timezone of <code>XMLGregorianCalendar</code> to be created.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from specified values.
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         */
-        public XMLGregorianCalendar newXMLGregorianCalendar(
-                final int year,
-                final int month,
-                final int day,
-                final int hour,
-                final int minute,
-                final int second,
-                final int millisecond,
-                final int timezone) {
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param hour of <code>XMLGregorianCalendar</code> to be created.
+     * @param minute of <code>XMLGregorianCalendar</code> to be created.
+     * @param second of <code>XMLGregorianCalendar</code> to be created.
+     * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from specified values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendar(
+            final int year,
+            final int month,
+            final int day,
+            final int hour,
+            final int minute,
+            final int second,
+            final int millisecond,
+            final int timezone) {
 
-                // year may be undefined
-                BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null;
+            // year may be undefined
+            BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null;
 
-                // millisecond may be undefined
-                // millisecond must be >= 0 millisecond <= 1000
-                BigDecimal realMillisecond = null; // undefined value
-                if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
-                        if (millisecond < 0 || millisecond > 1000) {
-                                throw new IllegalArgumentException(
-                                                        "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar("
-                                                        + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)"
-                                                        + "with invalid millisecond: " + millisecond
-                                                        );
-                        }
+            // millisecond may be undefined
+            // millisecond must be >= 0 millisecond <= 1000
+            BigDecimal realMillisecond = null; // undefined value
+            if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
+                    if (millisecond < 0 || millisecond > 1000) {
+                            throw new IllegalArgumentException(
+                                                    "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar("
+                                                    + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)"
+                                                    + "with invalid millisecond: " + millisecond
+                                                    );
+                    }
 
-                        realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3);
-                }
+                    realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3);
+            }
 
-                return newXMLGregorianCalendar(
-                        realYear,
-                        month,
-                        day,
-                        hour,
-                        minute,
-                        second,
-                        realMillisecond,
-                        timezone
-                );
-        }
+            return newXMLGregorianCalendar(
+                    realYear,
+                    month,
+                    day,
+                    hour,
+                    minute,
+                    second,
+                    realMillisecond,
+                    timezone
+            );
+    }
 
-        /**
-         * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
-         *
-         * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
-         * with <code>month</code> and <code>day</code> parameters set to
-         * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
-         *
+    /**
+     * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
+     *
+     * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
+     * with <code>month</code> and <code>day</code> parameters set to
+     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
-         * @param year of <code>XMLGregorianCalendar</code> to be created.
-         * @param month of <code>XMLGregorianCalendar</code> to be created.
-         * @param day of <code>XMLGregorianCalendar</code> to be created.
-         * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from parameter values.
-         *
-         * @see DatatypeConstants#FIELD_UNDEFINED
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         */
-        public XMLGregorianCalendar newXMLGregorianCalendarDate(
-                final int year,
-                final int month,
-                final int day,
-                final int timezone) {
+     * @param year of <code>XMLGregorianCalendar</code> to be created.
+     * @param month of <code>XMLGregorianCalendar</code> to be created.
+     * @param day of <code>XMLGregorianCalendar</code> to be created.
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarDate(
+            final int year,
+            final int month,
+            final int day,
+            final int timezone) {
 
-                return newXMLGregorianCalendar(
-                        year,
-                        month,
-                        day,
-                        DatatypeConstants.FIELD_UNDEFINED, // hour
-                        DatatypeConstants.FIELD_UNDEFINED, // minute
-                        DatatypeConstants.FIELD_UNDEFINED, // second
-                        DatatypeConstants.FIELD_UNDEFINED, // millisecond
-                        timezone);
-                }
+            return newXMLGregorianCalendar(
+                    year,
+                    month,
+                    day,
+                    DatatypeConstants.FIELD_UNDEFINED, // hour
+                    DatatypeConstants.FIELD_UNDEFINED, // minute
+                    DatatypeConstants.FIELD_UNDEFINED, // second
+                    DatatypeConstants.FIELD_UNDEFINED, // millisecond
+                    timezone);
+            }
 
-        /**
-         * <p>Create a Java instance of XML Schema builtin datatype <code>time</code>.</p>
-         *
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype <code>time</code>.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
-         * @param hours number of hours
-         * @param minutes number of minutes
-         * @param seconds number of seconds
-         * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from parameter values.
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         *
-         * @see DatatypeConstants#FIELD_UNDEFINED
-         */
-        public XMLGregorianCalendar newXMLGregorianCalendarTime(
-                final int hours,
-                final int minutes,
-                final int seconds,
-                final int timezone) {
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final int timezone) {
 
-                return newXMLGregorianCalendar(
-                        DatatypeConstants.FIELD_UNDEFINED, // Year
-                        DatatypeConstants.FIELD_UNDEFINED, // Month
-                        DatatypeConstants.FIELD_UNDEFINED, // Day
-                        hours,
-                        minutes,
-                        seconds,
-                        DatatypeConstants.FIELD_UNDEFINED, //Millisecond
-                        timezone);
-        }
+            return newXMLGregorianCalendar(
+                    DatatypeConstants.FIELD_UNDEFINED, // Year
+                    DatatypeConstants.FIELD_UNDEFINED, // Month
+                    DatatypeConstants.FIELD_UNDEFINED, // Day
+                    hours,
+                    minutes,
+                    seconds,
+                    DatatypeConstants.FIELD_UNDEFINED, //Millisecond
+                    timezone);
+    }
 
-        /**
-         * <p>Create a Java instance of XML Schema builtin datatype time.</p>
-         *
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
+     *
      * <p>A <code>null</code> value indicates that field is not set.</p>
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
-         * @param hours number of hours
-         * @param minutes number of minutes
-         * @param seconds number of seconds
-         * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
-         * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from parameter values.
-         *
-         * @see DatatypeConstants#FIELD_UNDEFINED
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         */
-        public XMLGregorianCalendar newXMLGregorianCalendarTime(
-                final int hours,
-                final int minutes,
-                final int seconds,
-                final BigDecimal fractionalSecond,
-                final int timezone) {
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final BigDecimal fractionalSecond,
+            final int timezone) {
 
-                return newXMLGregorianCalendar(
-                        null, // year
-                        DatatypeConstants.FIELD_UNDEFINED, // month
-                        DatatypeConstants.FIELD_UNDEFINED, // day
-                        hours,
-                        minutes,
-                        seconds,
-                        fractionalSecond,
-                        timezone);
-                }
+            return newXMLGregorianCalendar(
+                    null, // year
+                    DatatypeConstants.FIELD_UNDEFINED, // month
+                    DatatypeConstants.FIELD_UNDEFINED, // day
+                    hours,
+                    minutes,
+                    seconds,
+                    fractionalSecond,
+                    timezone);
+            }
 
-        /**
-         * <p>Create a Java instance of XML Schema builtin datatype time.</p>
-         *
+    /**
+     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
+     *
      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
      *
-         * @param hours number of hours
-         * @param minutes number of minutes
-         * @param seconds number of seconds
-         * @param milliseconds number of milliseconds
-         * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
-         *
-         * @return <code>XMLGregorianCalendar</code> created from parameter values.
-         *
-         * @see DatatypeConstants#FIELD_UNDEFINED
-         *
-         * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
-         *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
-         *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
-         *   as determined by {@link XMLGregorianCalendar#isValid()}.
-         */
-        public XMLGregorianCalendar newXMLGregorianCalendarTime(
-                final int hours,
-                final int minutes,
-                final int seconds,
-                final int milliseconds,
-                final int timezone) {
+     * @param hours number of hours
+     * @param minutes number of minutes
+     * @param seconds number of seconds
+     * @param milliseconds number of milliseconds
+     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
+     *
+     * @return <code>XMLGregorianCalendar</code> created from parameter values.
+     *
+     * @see DatatypeConstants#FIELD_UNDEFINED
+     *
+     * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
+     *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
+     *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
+     *   as determined by {@link XMLGregorianCalendar#isValid()}.
+     */
+    public XMLGregorianCalendar newXMLGregorianCalendarTime(
+            final int hours,
+            final int minutes,
+            final int seconds,
+            final int milliseconds,
+            final int timezone) {
 
-                // millisecond may be undefined
-                // millisecond must be >= 0 millisecond <= 1000
-                BigDecimal realMilliseconds = null; // undefined value
-                if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) {
-                        if (milliseconds < 0 || milliseconds > 1000) {
-                                throw new IllegalArgumentException(
-                                                        "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime("
-                                                        + "int hours, int minutes, int seconds, int milliseconds, int timezone)"
-                                                        + "with invalid milliseconds: " + milliseconds
-                                                        );
-                        }
+            // millisecond may be undefined
+            // millisecond must be >= 0 millisecond <= 1000
+            BigDecimal realMilliseconds = null; // undefined value
+            if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) {
+                    if (milliseconds < 0 || milliseconds > 1000) {
+                            throw new IllegalArgumentException(
+                                                    "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime("
+                                                    + "int hours, int minutes, int seconds, int milliseconds, int timezone)"
+                                                    + "with invalid milliseconds: " + milliseconds
+                                                    );
+                    }
 
-                        realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3);
-                }
+                    realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3);
+            }
 
-                return newXMLGregorianCalendarTime(
-                        hours,
-                        minutes,
-                        seconds,
-                        realMilliseconds,
-                        timezone
-                );
-        }
+            return newXMLGregorianCalendarTime(
+                    hours,
+                    minutes,
+                    seconds,
+                    realMilliseconds,
+                    timezone
+            );
+    }
 }
--- a/jaxp/src/javax/xml/datatype/FactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/datatype/FactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,14 +26,12 @@
 package javax.xml.datatype;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
 import java.util.Properties;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.net.URL;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
  * <p>Implements pluggable Datatypes.</p>
@@ -54,19 +52,19 @@
     /**
      * Cache for properties in java.home/lib/jaxp.properties
      */
-    static Properties cacheProps = new Properties();
+    private final static Properties cacheProps = new Properties();
 
     /**
      * Flag indicating if properties from java.home/lib/jaxp.properties
      * have been cached.
      */
-    static volatile boolean firstTime = true;
+    private static volatile boolean firstTime = true;
 
     /**
      * Security support class use to check access control before
      * getting certain system resources.
      */
-    static SecuritySupport ss = new SecuritySupport();
+    private final static SecuritySupport ss = new SecuritySupport();
 
     // Define system property "jaxp.debug" to get output
     static {
@@ -99,31 +97,31 @@
      *
      * Use bootstrap classLoader if cl = null and useBSClsLoader is true
      */
-    static private Class getProviderClass(String className, ClassLoader cl,
+    static private Class<?> getProviderClass(String className, ClassLoader cl,
             boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException
     {
         try {
             if (cl == null) {
                 if (useBSClsLoader) {
-                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                    return Class.forName(className, false, FactoryFinder.class.getClassLoader());
                 } else {
                     cl = ss.getContextClassLoader();
                     if (cl == null) {
                         throw new ClassNotFoundException();
                     }
                     else {
-                        return cl.loadClass(className);
+                        return Class.forName(className, false, cl);
                     }
                 }
             }
             else {
-                return cl.loadClass(className);
+                return Class.forName(className, false, cl);
             }
         }
         catch (ClassNotFoundException e1) {
             if (doFallback) {
                 // Use current class loader - should always be bootstrap CL
-                return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                return Class.forName(className, false, FactoryFinder.class.getClassLoader());
             }
             else {
                 throw e1;
@@ -135,6 +133,9 @@
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -144,16 +145,19 @@
      * @param doFallback True if the current ClassLoader should be tried as
      * a fallback if the class is not found using cl
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback)
+        throws  DatatypeConfigurationException
     {
-        return newInstance(className, cl, doFallback, false);
+        return newInstance(type, className, cl, doFallback, false);
     }
 
     /**
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -166,9 +170,12 @@
      * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter
      * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
+            boolean doFallback, boolean useBSClsLoader)
+        throws DatatypeConfigurationException
     {
+        assert type != null;
+
         // make sure we have access to restricted packages
         if (System.getSecurityManager() != null) {
             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@@ -178,20 +185,23 @@
         }
 
         try {
-            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            if (!type.isAssignableFrom(providerClass)) {
+                throw new ClassCastException(className + " cannot be cast to " + type.getName());
+            }
             Object instance = providerClass.newInstance();
             if (debug) {    // Extra check to avoid computing cl strings
                 dPrint("created new instance of " + providerClass +
                        " using ClassLoader: " + cl);
             }
-            return instance;
+            return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
-            throw new ConfigurationError(
+            throw new DatatypeConfigurationException(
                 "Provider " + className + " not found", x);
         }
         catch (Exception x) {
-            throw new ConfigurationError(
+            throw new DatatypeConfigurationException(
                 "Provider " + className + " could not be instantiated: " + x,
                 x);
         }
@@ -202,16 +212,17 @@
      * entry point.
      * @return Class object of factory, never null
      *
-     * @param factoryId             Name of the factory to find, same as
-     *                              a property name
+     * @param type                  Base class / Service interface  of the
+     *                              factory to find.
      * @param fallbackClassName     Implementation class name, if nothing else
      *                              is found.  Use null to mean no fallback.
      *
      * Package private so this code can be shared.
      */
-    static Object find(String factoryId, String fallbackClassName)
-        throws ConfigurationError
+    static <T> T find(Class<T> type, String fallbackClassName)
+        throws DatatypeConfigurationException
     {
+        final String factoryId = type.getName();
         dPrint("find factoryId =" + factoryId);
 
         // Use the system property first
@@ -219,7 +230,7 @@
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
                 dPrint("found system property, value=" + systemProp);
-                return newInstance(systemProp, null, true);
+                return newInstance(type, systemProp, null, true);
             }
         }
         catch (SecurityException se) {
@@ -228,7 +239,6 @@
 
         // try to read from $java.home/lib/jaxp.properties
         try {
-            String factoryClassName = null;
             if (firstTime) {
                 synchronized (cacheProps) {
                     if (firstTime) {
@@ -243,11 +253,11 @@
                     }
                 }
             }
-            factoryClassName = cacheProps.getProperty(factoryId);
+            final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
                 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
-                return newInstance(factoryClassName, null, true);
+                return newInstance(type, factoryClassName, null, true);
             }
         }
         catch (Exception ex) {
@@ -255,112 +265,46 @@
         }
 
         // Try Jar Service Provider Mechanism
-        Object provider = findJarServiceProvider(factoryId);
+        final T provider = findServiceProvider(type);
         if (provider != null) {
             return provider;
         }
         if (fallbackClassName == null) {
-            throw new ConfigurationError(
-                "Provider for " + factoryId + " cannot be found", null);
+            throw new DatatypeConfigurationException(
+                "Provider for " + factoryId + " cannot be found");
         }
 
         dPrint("loaded from fallback value: " + fallbackClassName);
-        return newInstance(fallbackClassName, null, true);
+        return newInstance(type, fallbackClassName, null, true);
     }
 
     /*
-     * Try to find provider using Jar Service Provider Mechanism
+     * Try to find provider using the ServiceLoader API
+     *
+     * @param type Base class / Service interface  of the factory to find.
      *
      * @return instance of provider class if found or null
      */
-    private static Object findJarServiceProvider(String factoryId)
-        throws ConfigurationError
+    private static <T> T findServiceProvider(final Class<T> type)
+            throws DatatypeConfigurationException
     {
-        String serviceId = "META-INF/services/" + factoryId;
-        InputStream is = null;
-
-        // First try the Context ClassLoader
-        ClassLoader cl = ss.getContextClassLoader();
-        boolean useBSClsLoader = false;
-        if (cl != null) {
-            is = ss.getResourceAsStream(cl, serviceId);
-
-            // If no provider found then try the current ClassLoader
-            if (is == null) {
-                cl = FactoryFinder.class.getClassLoader();
-                is = ss.getResourceAsStream(cl, serviceId);
-                useBSClsLoader = true;
-            }
-        } else {
-            // No Context ClassLoader, try the current ClassLoader
-            cl = FactoryFinder.class.getClassLoader();
-            is = ss.getResourceAsStream(cl, serviceId);
-            useBSClsLoader = true;
-        }
-
-        if (is == null) {
-            // No provider found
-            return null;
-        }
-
-        if (debug) {    // Extra check to avoid computing cl strings
-            dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl);
-        }
-
-        BufferedReader rd;
-        try {
-            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-        }
-        catch (java.io.UnsupportedEncodingException e) {
-            rd = new BufferedReader(new InputStreamReader(is));
-        }
-
-        String factoryClassName = null;
         try {
-            // XXX Does not handle all possible input as specified by the
-            // Jar Service Provider specification
-            factoryClassName = rd.readLine();
-            rd.close();
-        } catch (IOException x) {
-            // No provider found
-            return null;
-        }
-
-        if (factoryClassName != null && !"".equals(factoryClassName)) {
-            dPrint("found in resource, value=" + factoryClassName);
-
-            // Note: here we do not want to fall back to the current
-            // ClassLoader because we want to avoid the case where the
-            // resource file was found using one ClassLoader and the
-            // provider class was instantiated using a different one.
-            return newInstance(factoryClassName, cl, false, useBSClsLoader);
-        }
-
-        // No provider found
-        return null;
-    }
-
-    static class ConfigurationError extends Error {
-        private Exception exception;
-
-        /**
-         * Construct a new instance with the specified detail string and
-         * exception.
-         */
-        ConfigurationError(String msg, Exception x) {
-            super(msg);
-            this.exception = x;
-        }
-
-        Exception getException() {
-            return exception;
-        }
-        /**
-        * use the exception chaining mechanism of JDK1.4
-        */
-        @Override
-        public Throwable getCause() {
-            return exception;
+            return AccessController.doPrivileged(new PrivilegedAction<T>() {
+                public T run() {
+                    final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
+                    final Iterator<T> iterator = serviceLoader.iterator();
+                    if (iterator.hasNext()) {
+                        return iterator.next();
+                    } else {
+                        return null;
+                    }
+                }
+            });
+        } catch(ServiceConfigurationError e) {
+            final DatatypeConfigurationException error =
+                    new DatatypeConfigurationException(
+                        "Provider for " + type + " cannot be found", e);
+            throw error;
         }
     }
 
--- a/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,9 +40,6 @@
 
 public abstract class DocumentBuilderFactory {
 
-    /** The default property name according to the JAXP spec */
-    private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.DocumentBuilderFactory";
-
     private boolean validating = false;
     private boolean namespaceAware = false;
     private boolean whitespace = false;
@@ -50,8 +47,6 @@
     private boolean ignoreComments = false;
     private boolean coalescing = false;
 
-    private boolean canonicalState = false;
-
     /**
      * <p>Protected constructor to prevent instantiation.
      * Use {@link #newInstance()}.</p>
@@ -85,14 +80,12 @@
      * of any property in jaxp.properties after it has been read for the first time.
      * </li>
      * <li>
-     * Use the Services API (as detailed in the JAR specification), if
-     * available, to determine the classname. The Services API will look
-     * for a classname in the file
-     * <code>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</code>
-     * in jars available to the runtime.
+     * Uses the service-provider loading facilities, defined by the
+     * {@link java.util.ServiceLoader} class, to attempt to locate and load an
+     * implementation of the service.
      * </li>
      * <li>
-     * Platform default <code>DocumentBuilderFactory</code> instance.
+     * Otherwise, the system-default implementation is returned.
      * </li>
      * </ul>
      *
@@ -113,21 +106,16 @@
      *
      * @return New instance of a <code>DocumentBuilderFactory</code>
      *
-     * @throws FactoryConfigurationError if the implementation is not
-     *   available or cannot be instantiated.
+     * @throws FactoryConfigurationError in case of {@linkplain
+     * java.util.ServiceConfigurationError service configuration error} or if
+     * the implementation is not available or cannot be instantiated.
      */
     public static DocumentBuilderFactory newInstance() {
-        try {
-            return (DocumentBuilderFactory) FactoryFinder.find(
+        return FactoryFinder.find(
                 /* The default property name according to the JAXP spec */
-                "javax.xml.parsers.DocumentBuilderFactory",
+                DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory"
                 /* The fallback implementation class name */
                 "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new FactoryConfigurationError(e.getException(),
-                                                e.getMessage());
-        }
-
     }
 
     /**
@@ -165,13 +153,9 @@
      * @since 1.6
      */
     public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){
-        try {
             //do not fallback if given classloader can't find the class, throw exception
-            return (DocumentBuilderFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false);
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new FactoryConfigurationError(e.getException(),
-                                                e.getMessage());
-        }
+            return FactoryFinder.newInstance(DocumentBuilderFactory.class,
+                        factoryClassName, classLoader, false);
     }
 
     /**
@@ -391,75 +375,64 @@
     public abstract Object getAttribute(String name)
                 throws IllegalArgumentException;
 
-        /**
-         * <p>Set a feature for this <code>DocumentBuilderFactory</code> and <code>DocumentBuilder</code>s created by this factory.</p>
-         *
-         * <p>
-         * Feature names are fully qualified {@link java.net.URI}s.
-         * Implementations may define their own features.
-         * A {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
-         * <code>DocumentBuilder</code>s it creates cannot support the feature.
-         * It is possible for a <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
-         * </p>
-         *
-         * <p>
-         * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
-         * When the feature is:</p>
-         * <ul>
-         *   <li>
-         *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
-         *     Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
-         *     If XML processing is limited for security reasons, it will be reported via a call to the registered
-         *    {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
-         *     See {@link  DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}.
-         *   </li>
-         *   <li>
-         *     <code>false</code>: the implementation will processing XML according to the XML specifications without
-         *     regard to possible implementation limits.
-         *   </li>
-         * </ul>
-         *
-         * @param name Feature name.
-         * @param value Is feature state <code>true</code> or <code>false</code>.
-         *
-         * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code> or the <code>DocumentBuilder</code>s
-         *   it creates cannot support this feature.
+    /**
+     * <p>Set a feature for this <code>DocumentBuilderFactory</code> and <code>DocumentBuilder</code>s created by this factory.</p>
+     *
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * A {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
+     * <code>DocumentBuilder</code>s it creates cannot support the feature.
+     * It is possible for a <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * <p>
+     * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is:</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
+     *     Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *    {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
+     *     See {@link  DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}.
+     *   </li>
+     *   <li>
+     *     <code>false</code>: the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
+     * @param name Feature name.
+     * @param value Is feature state <code>true</code> or <code>false</code>.
+     *
+     * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code> or the <code>DocumentBuilder</code>s
+     *   it creates cannot support this feature.
      * @throws NullPointerException If the <code>name</code> parameter is null.
-         */
-        public abstract void setFeature(String name, boolean value)
-                throws ParserConfigurationException;
+     */
+    public abstract void setFeature(String name, boolean value)
+            throws ParserConfigurationException;
 
-        /**
-         * <p>Get the state of the named feature.</p>
-         *
-         * <p>
-         * Feature names are fully qualified {@link java.net.URI}s.
-         * Implementations may define their own features.
-         * An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
-         * <code>DocumentBuilder</code>s it creates cannot support the feature.
-         * It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
-         * </p>
-         *
-         * @param name Feature name.
-         *
-         * @return State of the named feature.
-         *
-         * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code>
-         *   or the <code>DocumentBuilder</code>s it creates cannot support this feature.
-         */
-        public abstract boolean getFeature(String name)
-                throws ParserConfigurationException;
-
-
-    /** <p>Get current state of canonicalization.</p>
+    /**
+     * <p>Get the state of the named feature.</p>
      *
-     * @return current state canonicalization control
+     * <p>
+     * Feature names are fully qualified {@link java.net.URI}s.
+     * Implementations may define their own features.
+     * An {@link ParserConfigurationException} is thrown if this <code>DocumentBuilderFactory</code> or the
+     * <code>DocumentBuilder</code>s it creates cannot support the feature.
+     * It is possible for an <code>DocumentBuilderFactory</code> to expose a feature value but be unable to change its state.
+     * </p>
+     *
+     * @param name Feature name.
+     *
+     * @return State of the named feature.
+     *
+     * @throws ParserConfigurationException if this <code>DocumentBuilderFactory</code>
+     *   or the <code>DocumentBuilder</code>s it creates cannot support this feature.
      */
-    /*
-    public boolean getCanonicalization() {
-        return canonicalState;
-    }
-    */
+    public abstract boolean getFeature(String name)
+            throws ParserConfigurationException;
 
 
     /**
@@ -488,17 +461,6 @@
 
     }
 
-    /* <p>Set canonicalization control to <code>true</code> or
-     * </code>false</code>.</p>
-     *
-     * @param state of canonicalization
-     */
-    /*
-    public void setCanonicalization(boolean state) {
-        canonicalState = state;
-    }
-    */
-
     /**
      * <p>Set the {@link Schema} to be used by parsers created
      * from this factory.
--- a/jaxp/src/javax/xml/parsers/FactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/parsers/FactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,16 @@
 
 package javax.xml.parsers;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
 import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
- * <p>Implements pluggable Datatypes.</p>
+ * <p>Implements pluggable Parsers.</p>
  *
  * <p>This class is duplicated for each JAXP subpackage so keep it in
  * sync.  It is package private for secure class loading.</p>
@@ -51,7 +52,7 @@
     /**
      * Cache for properties in java.home/lib/jaxp.properties
      */
-    static Properties cacheProps = new Properties();
+    private static final Properties cacheProps = new Properties();
 
     /**
      * Flag indicating if properties from java.home/lib/jaxp.properties
@@ -63,7 +64,7 @@
      * Security support class use to check access control before
      * getting certain system resources.
      */
-    static SecuritySupport ss = new SecuritySupport();
+    private static final SecuritySupport ss = new SecuritySupport();
 
     // Define system property "jaxp.debug" to get output
     static {
@@ -96,31 +97,31 @@
      *
      * Use bootstrap classLoader if cl = null and useBSClsLoader is true
      */
-    static private Class getProviderClass(String className, ClassLoader cl,
+    static private Class<?> getProviderClass(String className, ClassLoader cl,
             boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException
     {
         try {
             if (cl == null) {
                 if (useBSClsLoader) {
-                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                    return Class.forName(className, false, FactoryFinder.class.getClassLoader());
                 } else {
                     cl = ss.getContextClassLoader();
                     if (cl == null) {
                         throw new ClassNotFoundException();
                     }
                     else {
-                        return cl.loadClass(className);
+                        return Class.forName(className, false, cl);
                     }
                 }
             }
             else {
-                return cl.loadClass(className);
+                return Class.forName(className, false, cl);
             }
         }
         catch (ClassNotFoundException e1) {
             if (doFallback) {
                 // Use current class loader - should always be bootstrap CL
-                return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                return Class.forName(className, false, FactoryFinder.class.getClassLoader());
             }
             else {
                 throw e1;
@@ -132,6 +133,9 @@
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -141,16 +145,20 @@
      * @param doFallback True if the current ClassLoader should be tried as
      * a fallback if the class is not found using cl
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
+                             boolean doFallback)
+        throws FactoryConfigurationError
     {
-        return newInstance(className, cl, doFallback, false);
+        return newInstance(type, className, cl, doFallback, false);
     }
 
     /**
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -163,9 +171,11 @@
      * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter
      * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
+                             boolean doFallback, boolean useBSClsLoader)
+        throws FactoryConfigurationError
     {
+        assert type != null;
         // make sure we have access to restricted packages
         if (System.getSecurityManager() != null) {
             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@@ -175,22 +185,24 @@
         }
 
         try {
-            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            if (!type.isAssignableFrom(providerClass)) {
+                throw new ClassCastException(className + " cannot be cast to " + type.getName());
+            }
             Object instance = providerClass.newInstance();
             if (debug) {    // Extra check to avoid computing cl strings
                 dPrint("created new instance of " + providerClass +
                        " using ClassLoader: " + cl);
             }
-            return instance;
+            return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
-            throw new ConfigurationError(
-                "Provider " + className + " not found", x);
+            throw new FactoryConfigurationError(x,
+                "Provider " + className + " not found");
         }
         catch (Exception x) {
-            throw new ConfigurationError(
-                "Provider " + className + " could not be instantiated: " + x,
-                x);
+            throw new FactoryConfigurationError(x,
+                "Provider " + className + " could not be instantiated: " + x);
         }
     }
 
@@ -199,16 +211,17 @@
      * entry point.
      * @return Class object of factory, never null
      *
-     * @param factoryId             Name of the factory to find, same as
-     *                              a property name
+     * @param type                  Base class / Service interface  of the
+     *                              factory to find.
      * @param fallbackClassName     Implementation class name, if nothing else
      *                              is found.  Use null to mean no fallback.
      *
      * Package private so this code can be shared.
      */
-    static Object find(String factoryId, String fallbackClassName)
-        throws ConfigurationError
+    static <T> T find(Class<T> type, String fallbackClassName)
+        throws FactoryConfigurationError
     {
+        final String factoryId = type.getName();
         dPrint("find factoryId =" + factoryId);
 
         // Use the system property first
@@ -216,7 +229,7 @@
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
                 dPrint("found system property, value=" + systemProp);
-                return newInstance(systemProp, null, true);
+                return newInstance(type, systemProp, null, true);
             }
         }
         catch (SecurityException se) {
@@ -225,7 +238,6 @@
 
         // try to read from $java.home/lib/jaxp.properties
         try {
-            String factoryClassName = null;
             if (firstTime) {
                 synchronized (cacheProps) {
                     if (firstTime) {
@@ -240,11 +252,11 @@
                     }
                 }
             }
-            factoryClassName = cacheProps.getProperty(factoryId);
+            final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
                 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
-                return newInstance(factoryClassName, null, true);
+                return newInstance(type, factoryClassName, null, true);
             }
         }
         catch (Exception ex) {
@@ -252,112 +264,52 @@
         }
 
         // Try Jar Service Provider Mechanism
-        Object provider = findJarServiceProvider(factoryId);
+        T provider = findServiceProvider(type);
         if (provider != null) {
             return provider;
         }
         if (fallbackClassName == null) {
-            throw new ConfigurationError(
-                "Provider for " + factoryId + " cannot be found", null);
+            throw new FactoryConfigurationError(
+                "Provider for " + factoryId + " cannot be found");
         }
 
         dPrint("loaded from fallback value: " + fallbackClassName);
-        return newInstance(fallbackClassName, null, true);
+        return newInstance(type, fallbackClassName, null, true);
     }
 
     /*
-     * Try to find provider using Jar Service Provider Mechanism
+     * Try to find provider using the ServiceLoader API
+     *
+     * @param type Base class / Service interface  of the factory to find.
      *
      * @return instance of provider class if found or null
      */
-    private static Object findJarServiceProvider(String factoryId)
-        throws ConfigurationError
-    {
-        String serviceId = "META-INF/services/" + factoryId;
-        InputStream is = null;
-
-        // First try the Context ClassLoader
-        ClassLoader cl = ss.getContextClassLoader();
-        boolean useBSClsLoader = false;
-        if (cl != null) {
-            is = ss.getResourceAsStream(cl, serviceId);
-
-            // If no provider found then try the current ClassLoader
-            if (is == null) {
-                cl = FactoryFinder.class.getClassLoader();
-                is = ss.getResourceAsStream(cl, serviceId);
-                useBSClsLoader = true;
-            }
-        } else {
-            // No Context ClassLoader, try the current ClassLoader
-            cl = FactoryFinder.class.getClassLoader();
-            is = ss.getResourceAsStream(cl, serviceId);
-            useBSClsLoader = true;
-        }
-
-        if (is == null) {
-            // No provider found
-            return null;
-        }
-
-        if (debug) {    // Extra check to avoid computing cl strings
-            dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl);
-        }
-
-        BufferedReader rd;
-        try {
-            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-        }
-        catch (java.io.UnsupportedEncodingException e) {
-            rd = new BufferedReader(new InputStreamReader(is));
-        }
-
-        String factoryClassName = null;
+    private static <T> T findServiceProvider(final Class<T> type) {
         try {
-            // XXX Does not handle all possible input as specified by the
-            // Jar Service Provider specification
-            factoryClassName = rd.readLine();
-            rd.close();
-        } catch (IOException x) {
-            // No provider found
-            return null;
-        }
-
-        if (factoryClassName != null && !"".equals(factoryClassName)) {
-            dPrint("found in resource, value=" + factoryClassName);
-
-            // Note: here we do not want to fall back to the current
-            // ClassLoader because we want to avoid the case where the
-            // resource file was found using one ClassLoader and the
-            // provider class was instantiated using a different one.
-            return newInstance(factoryClassName, cl, false, useBSClsLoader);
-        }
-
-        // No provider found
-        return null;
-    }
-
-    static class ConfigurationError extends Error {
-        private Exception exception;
-
-        /**
-         * Construct a new instance with the specified detail string and
-         * exception.
-         */
-        ConfigurationError(String msg, Exception x) {
-            super(msg);
-            this.exception = x;
-        }
-
-        Exception getException() {
-            return exception;
-        }
-        /**
-        * use the exception chaining mechanism of JDK1.4
-        */
-        @Override
-        public Throwable getCause() {
-            return exception;
+            return AccessController.doPrivileged(new PrivilegedAction<T>() {
+                public T run() {
+                    final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
+                    final Iterator<T> iterator = serviceLoader.iterator();
+                    if (iterator.hasNext()) {
+                        return iterator.next();
+                    } else {
+                        return null;
+                    }
+                 }
+            });
+        } catch(ServiceConfigurationError e) {
+            // It is not possible to wrap an error directly in
+            // FactoryConfigurationError - so we need to wrap the
+            // ServiceConfigurationError in a RuntimeException.
+            // The alternative would be to modify the logic in
+            // FactoryConfigurationError to allow setting a
+            // Throwable as the cause, but that could cause
+            // compatibility issues down the road.
+            final RuntimeException x = new RuntimeException(
+                    "Provider for " + type + " cannot be created", e);
+            final FactoryConfigurationError error =
+                    new FactoryConfigurationError(x, x.getMessage());
+            throw error;
         }
     }
 
--- a/jaxp/src/javax/xml/parsers/SAXParserFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/parsers/SAXParserFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 package javax.xml.parsers;
 
 import javax.xml.validation.Schema;
-
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXNotRecognizedException;
 import org.xml.sax.SAXNotSupportedException;
@@ -42,8 +41,6 @@
  *
  */
 public abstract class SAXParserFactory {
-    /** The default property name according to the JAXP spec */
-    private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory";
 
     /**
      * <p>Should Parsers be validating?</p>
@@ -87,14 +84,12 @@
      * of any property in jaxp.properties after it has been read for the first time.
      * </li>
      * <li>
-     * Use the Services API (as detailed in the JAR specification), if
-     * available, to determine the classname. The Services API will look
-     * for a classname in the file
-     * <code>META-INF/services/javax.xml.parsers.SAXParserFactory</code>
-     * in jars available to the runtime.
+     * Use the service-provider loading facilities, defined by the
+     * {@link java.util.ServiceLoader} class, to attempt to locate and load an
+     * implementation of the service.
      * </li>
      * <li>
-     * Platform default <code>SAXParserFactory</code> instance.
+     * Otherwise the system-default implementation is returned.
      * </li>
      * </ul>
      *
@@ -109,7 +104,7 @@
      * this method to print a lot of debug messages
      * to <code>System.err</code> about what it is doing and where it is looking at.</p>
      *
-     * <p> If you have problems loading {@link DocumentBuilder}s, try:</p>
+     * <p> If you have problems loading {@link SAXParser}s, try:</p>
      * <pre>
      * java -Djaxp.debug=1 YourProgram ....
      * </pre>
@@ -117,21 +112,17 @@
      *
      * @return A new instance of a SAXParserFactory.
      *
-     * @throws FactoryConfigurationError if the implementation is
-     *   not available or cannot be instantiated.
+     * @throws FactoryConfigurationError in case of {@linkplain
+     * java.util.ServiceConfigurationError service configuration error} or if
+     * the implementation is not available or cannot be instantiated.
      */
 
     public static SAXParserFactory newInstance() {
-        try {
-            return (SAXParserFactory) FactoryFinder.find(
+        return FactoryFinder.find(
                 /* The default property name according to the JAXP spec */
-                "javax.xml.parsers.SAXParserFactory",
+                SAXParserFactory.class,
                 /* The fallback implementation class name */
                 "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl");
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new FactoryConfigurationError(e.getException(),
-                                                e.getMessage());
-        }
     }
 
     /**
@@ -169,13 +160,9 @@
      * @since 1.6
      */
     public static SAXParserFactory newInstance(String factoryClassName, ClassLoader classLoader){
-        try {
             //do not fallback if given classloader can't find the class, throw exception
-            return (SAXParserFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false);
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new FactoryConfigurationError(e.getException(),
-                                                e.getMessage());
-        }
+            return FactoryFinder.newInstance(SAXParserFactory.class,
+                    factoryClassName, classLoader, false);
     }
 
     /**
@@ -266,22 +253,22 @@
      * A list of the core features and properties can be found at
      * <a href="http://www.saxproject.org/">http://www.saxproject.org/</a></p>
      *
-         * <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
-         * When the feature is</p>
-         * <ul>
-         *   <li>
-         *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
-         *     Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources.
-         *     If XML processing is limited for security reasons, it will be reported via a call to the registered
-         *     {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
-         *     See {@link SAXParser} <code>parse</code> methods for handler specification.
-         *   </li>
-         *   <li>
-         *     When the feature is <code>false</code>, the implementation will processing XML according to the XML specifications without
-         *     regard to possible implementation limits.
-         *   </li>
-         * </ul>
-         *
+     * <p>All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature.
+     * When the feature is</p>
+     * <ul>
+     *   <li>
+     *     <code>true</code>: the implementation will limit XML processing to conform to implementation limits.
+     *     Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources.
+     *     If XML processing is limited for security reasons, it will be reported via a call to the registered
+     *     {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}.
+     *     See {@link SAXParser} <code>parse</code> methods for handler specification.
+     *   </li>
+     *   <li>
+     *     When the feature is <code>false</code>, the implementation will processing XML according to the XML specifications without
+     *     regard to possible implementation limits.
+     *   </li>
+     * </ul>
+     *
      * @param name The name of the feature to be set.
      * @param value The value of the feature to be set.
      *
@@ -320,17 +307,6 @@
                 SAXNotSupportedException;
 
 
-
-    /* <p>Get current state of canonicalization.</p>
-     *
-     * @return current state canonicalization control
-     */
-    /*
-    public boolean getCanonicalization() {
-        return canonicalState;
-    }
-    */
-
     /**
      * Gets the {@link Schema} object specified through
      * the {@link #setSchema(Schema schema)} method.
@@ -357,17 +333,6 @@
             );
     }
 
-    /** <p>Set canonicalization control to <code>true</code> or
-     * </code>false</code>.</p>
-     *
-     * @param state of canonicalization
-     */
-    /*
-    public void setCanonicalization(boolean state) {
-        canonicalState = state;
-    }
-    */
-
     /**
      * <p>Set the {@link Schema} to be used by parsers created
      * from this factory.</p>
@@ -400,7 +365,7 @@
      * Such configuration will cause a {@link SAXException}
      * exception when those properties are set on a {@link SAXParser}.</p>
      *
-     * <h4>Note for implmentors</h4>
+     * <h4>Note for implementors</h4>
      * <p>
      * A parser must be able to work with any {@link Schema}
      * implementation. However, parsers and schemas are allowed
--- a/jaxp/src/javax/xml/stream/FactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/stream/FactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,16 @@
 
 package javax.xml.stream;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
 import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
- * <p>Implements pluggable Datatypes.</p>
+ * <p>Implements pluggable streams.</p>
  *
  * <p>This class is duplicated for each JAXP subpackage so keep it in
  * sync.  It is package private for secure class loading.</p>
@@ -52,19 +53,19 @@
     /**
      * Cache for properties in java.home/lib/jaxp.properties
      */
-    static Properties cacheProps = new Properties();
+    final private static Properties cacheProps = new Properties();
 
     /**
      * Flag indicating if properties from java.home/lib/jaxp.properties
      * have been cached.
      */
-    static volatile boolean firstTime = true;
+    private static volatile boolean firstTime = true;
 
     /**
      * Security support class use to check access control before
      * getting certain system resources.
      */
-    static SecuritySupport ss = new SecuritySupport();
+    final private static SecuritySupport ss = new SecuritySupport();
 
     // Define system property "jaxp.debug" to get output
     static {
@@ -103,25 +104,25 @@
         try {
             if (cl == null) {
                 if (useBSClsLoader) {
-                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                    return Class.forName(className, false, FactoryFinder.class.getClassLoader());
                 } else {
                     cl = ss.getContextClassLoader();
                     if (cl == null) {
                         throw new ClassNotFoundException();
                     }
                     else {
-                        return cl.loadClass(className);
+                        return Class.forName(className, false, cl);
                     }
                 }
             }
             else {
-                return cl.loadClass(className);
+                return Class.forName(className, false, cl);
             }
         }
         catch (ClassNotFoundException e1) {
             if (doFallback) {
                 // Use current class loader - should always be bootstrap CL
-                return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                return Class.forName(className, false, FactoryFinder.class.getClassLoader());
             }
             else {
                 throw e1;
@@ -133,6 +134,9 @@
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -142,16 +146,19 @@
      * @param doFallback True if the current ClassLoader should be tried as
      * a fallback if the class is not found using cl
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl, boolean doFallback)
+        throws FactoryConfigurationError
     {
-        return newInstance(className, cl, doFallback, false);
+        return newInstance(type, className, cl, doFallback, false);
     }
 
     /**
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
+     *
      * @param className Name of the concrete class corresponding to the
      * service provider
      *
@@ -164,9 +171,12 @@
      * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter
      * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
+                              boolean doFallback, boolean useBSClsLoader)
+        throws FactoryConfigurationError
     {
+        assert type != null;
+
         // make sure we have access to restricted packages
         if (System.getSecurityManager() != null) {
             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@@ -176,20 +186,23 @@
         }
 
         try {
-            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            if (!type.isAssignableFrom(providerClass)) {
+                throw new ClassCastException(className + " cannot be cast to " + type.getName());
+            }
             Object instance = providerClass.newInstance();
             if (debug) {    // Extra check to avoid computing cl strings
                 dPrint("created new instance of " + providerClass +
                        " using ClassLoader: " + cl);
             }
-            return instance;
+            return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
-            throw new ConfigurationError(
+            throw new FactoryConfigurationError(
                 "Provider " + className + " not found", x);
         }
         catch (Exception x) {
-            throw new ConfigurationError(
+            throw new FactoryConfigurationError(
                 "Provider " + className + " could not be instantiated: " + x,
                 x);
         }
@@ -200,17 +213,18 @@
      *
      * @return Class object of factory, never null
      *
-     * @param factoryId             Name of the factory to find, same as
-     *                              a property name
+     * @param type                  Base class / Service interface  of the
+     *                              factory to find.
+     *
      * @param fallbackClassName     Implementation class name, if nothing else
      *                              is found.  Use null to mean no fallback.
      *
      * Package private so this code can be shared.
      */
-    static Object find(String factoryId, String fallbackClassName)
-        throws ConfigurationError
+    static <T> T find(Class<T> type, String fallbackClassName)
+        throws FactoryConfigurationError
     {
-        return find(factoryId, null, fallbackClassName);
+        return find(type, type.getName(), null, fallbackClassName);
     }
 
     /**
@@ -218,6 +232,9 @@
      * entry point.
      * @return Class object of factory, never null
      *
+     * @param type                  Base class / Service interface  of the
+     *                              factory to find.
+     *
      * @param factoryId             Name of the factory to find, same as
      *                              a property name
      *
@@ -229,8 +246,8 @@
      *
      * Package private so this code can be shared.
      */
-    static Object find(String factoryId, ClassLoader cl, String fallbackClassName)
-        throws ConfigurationError
+    static <T> T find(Class<T> type, String factoryId, ClassLoader cl, String fallbackClassName)
+        throws FactoryConfigurationError
     {
         dPrint("find factoryId =" + factoryId);
 
@@ -239,7 +256,9 @@
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
                 dPrint("found system property, value=" + systemProp);
-                return newInstance(systemProp, null, true);
+                // There's a bug here - because 'cl' is ignored.
+                // This will be handled separately.
+                return newInstance(type, systemProp, null, true);
             }
         }
         catch (SecurityException se) {
@@ -250,7 +269,6 @@
         // $java.home/lib/jaxp.properties if former not present
         String configFile = null;
         try {
-            String factoryClassName = null;
             if (firstTime) {
                 synchronized (cacheProps) {
                     if (firstTime) {
@@ -269,130 +287,80 @@
                             if (ss.doesFileExist(f)) {
                                 dPrint("Read properties file "+f);
                                 cacheProps.load(ss.getFileInputStream(f));
+                            }
+                        }
                     }
                 }
             }
-                }
-            }
-            factoryClassName = cacheProps.getProperty(factoryId);
+            final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
                 dPrint("found in " + configFile + " value=" + factoryClassName);
-                return newInstance(factoryClassName, null, true);
+                // There's a bug here - because 'cl' is ignored.
+                // This will be handled separately.
+                return newInstance(type, factoryClassName, null, true);
             }
         }
         catch (Exception ex) {
             if (debug) ex.printStackTrace();
         }
 
-        // Try Jar Service Provider Mechanism
-        Object provider = findJarServiceProvider(factoryId);
-        if (provider != null) {
-            return provider;
+        if (type.getName().equals(factoryId)) {
+            // Try Jar Service Provider Mechanism
+            final T provider = findServiceProvider(type);
+            if (provider != null) {
+                return provider;
+            }
+        } else {
+            // We're in the case where a 'custom' factoryId was provided,
+            // and in every case where that happens, we expect that
+            // fallbackClassName will be null.
+            assert fallbackClassName == null;
         }
         if (fallbackClassName == null) {
-            throw new ConfigurationError(
+            throw new FactoryConfigurationError(
                 "Provider for " + factoryId + " cannot be found", null);
         }
 
         dPrint("loaded from fallback value: " + fallbackClassName);
-        return newInstance(fallbackClassName, cl, true);
+        return newInstance(type, fallbackClassName, cl, true);
     }
 
     /*
-     * Try to find provider using Jar Service Provider Mechanism
+     * Try to find provider using the ServiceLoader API
+     *
+     * @param type Base class / Service interface  of the factory to find.
      *
      * @return instance of provider class if found or null
      */
-    private static Object findJarServiceProvider(String factoryId)
-        throws ConfigurationError
-    {
-        String serviceId = "META-INF/services/" + factoryId;
-        InputStream is = null;
-
-        // First try the Context ClassLoader
-        ClassLoader cl = ss.getContextClassLoader();
-        boolean useBSClsLoader = false;
-        if (cl != null) {
-            is = ss.getResourceAsStream(cl, serviceId);
-
-            // If no provider found then try the current ClassLoader
-            if (is == null) {
-                cl = FactoryFinder.class.getClassLoader();
-                is = ss.getResourceAsStream(cl, serviceId);
-                useBSClsLoader = true;
-            }
-        } else {
-            // No Context ClassLoader, try the current ClassLoader
-            cl = FactoryFinder.class.getClassLoader();
-            is = ss.getResourceAsStream(cl, serviceId);
-            useBSClsLoader = true;
-        }
-
-        if (is == null) {
-            // No provider found
-            return null;
-        }
-
-        if (debug) {    // Extra check to avoid computing cl strings
-            dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl);
-        }
-
-        BufferedReader rd;
-        try {
-            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-        }
-        catch (java.io.UnsupportedEncodingException e) {
-            rd = new BufferedReader(new InputStreamReader(is));
-        }
-
-        String factoryClassName = null;
+    private static <T> T findServiceProvider(final Class<T> type) {
         try {
-            // XXX Does not handle all possible input as specified by the
-            // Jar Service Provider specification
-            factoryClassName = rd.readLine();
-            rd.close();
-        } catch (IOException x) {
-            // No provider found
-            return null;
-        }
-
-        if (factoryClassName != null && !"".equals(factoryClassName)) {
-            dPrint("found in resource, value=" + factoryClassName);
-
-            // Note: here we do not want to fall back to the current
-            // ClassLoader because we want to avoid the case where the
-            // resource file was found using one ClassLoader and the
-            // provider class was instantiated using a different one.
-            return newInstance(factoryClassName, cl, false, useBSClsLoader);
-        }
-
-        // No provider found
-        return null;
-    }
-
-    static class ConfigurationError extends Error {
-        private Exception exception;
-
-        /**
-         * Construct a new instance with the specified detail string and
-         * exception.
-         */
-        ConfigurationError(String msg, Exception x) {
-            super(msg);
-            this.exception = x;
-        }
-
-        Exception getException() {
-            return exception;
-        }
-        /**
-        * use the exception chaining mechanism of JDK1.4
-        */
-        @Override
-        public Throwable getCause() {
-            return exception;
-        }
-    }
+            return AccessController.doPrivileged(new PrivilegedAction<T>() {
+                @Override
+                public T run() {
+                    final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
+                    final Iterator<T> iterator = serviceLoader.iterator();
+                    if (iterator.hasNext()) {
+                        return iterator.next();
+                    } else {
+                        return null;
+                    }
+                }
+            });
+        } catch(ServiceConfigurationError e) {
+            // It is not possible to wrap an error directly in
+            // FactoryConfigurationError - so we need to wrap the
+            // ServiceConfigurationError in a RuntimeException.
+            // The alternative would be to modify the logic in
+            // FactoryConfigurationError to allow setting a
+            // Throwable as the cause, but that could cause
+            // compatibility issues down the road.
+            final RuntimeException x = new RuntimeException(
+                    "Provider for " + type + " cannot be created", e);
+            final FactoryConfigurationError error =
+                    new FactoryConfigurationError(x, x.getMessage());
+            throw error;
+          }
+      }
 
 }
--- a/jaxp/src/javax/xml/stream/XMLEventFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/stream/XMLEventFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -23,14 +23,14 @@
  */
 
 /*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
+ * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
  */
 
 package javax.xml.stream;
-import javax.xml.stream.events.*;
+import java.util.Iterator;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.namespace.QName;
-import java.util.Iterator;
+import javax.xml.stream.events.*;
 /**
  * This interface defines a utility class for creating instances of
  * XMLEvents
@@ -54,48 +54,59 @@
 
 
   /**
-   * Create a new instance of the factory
+   * Creates a new instance of the factory in exactly the same manner as the
+   * {@link #newFactory()} method.
    * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
    */
   public static XMLEventFactory newInstance()
     throws FactoryConfigurationError
   {
-    return (XMLEventFactory) FactoryFinder.find(
-      JAXPFACTORYID,
-      DEFAULIMPL);
+    return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL);
   }
 
   /**
    * Create a new instance of the factory.
+   * <p>
    * This static method creates a new factory instance.
    * This method uses the following ordered lookup procedure to determine
    * the XMLEventFactory implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
    *   Use the javax.xml.stream.XMLEventFactory system property.
+   * </li>
+   * <li>
    *   Use the properties file "lib/stax.properties" in the JRE directory.
    *     This configuration file is in standard java.util.Properties format
    *     and contains the fully qualified name of the implementation class
    *     with the key being the system property defined above.
-   *   Use the Services API (as detailed in the JAR specification), if available,
-   *     to determine the classname. The Services API will look for a classname
-   *     in the file META-INF/services/javax.xml.stream.XMLEventFactory in jars
-   *     available to the runtime.
-   *   Platform default XMLEventFactory instance.
-   *
+   * </li>
+   * <li>
+   *   Use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   *   Otherwise, the system-default implementation is returned.
+   * </li>
+   * </ul>
+   * <p>
    *   Once an application has obtained a reference to a XMLEventFactory it
    *   can use the factory to configure and obtain stream instances.
-   *
+   * </p>
+   * <p>
    *   Note that this is a new method that replaces the deprecated newInstance() method.
    *     No changes in behavior are defined by this replacement method relative to
    *     the deprecated method.
-   *
-   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
+   * </p>
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    */
   public static XMLEventFactory newFactory()
     throws FactoryConfigurationError
   {
-    return (XMLEventFactory) FactoryFinder.find(
-      JAXPFACTORYID,
-      DEFAULIMPL);
+    return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL);
   }
 
   /**
@@ -116,40 +127,59 @@
   public static XMLEventFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null);
   }
 
   /**
    * Create a new instance of the factory.
    * If the classLoader argument is null, then the ContextClassLoader is used.
+   * <p>
+   * This method uses the following ordered lookup procedure to determine
+   * the XMLEventFactory implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
+   *   Use the value of the system property identified by {@code factoryId}.
+   * </li>
+   * <li>
+   *   Use the properties file "lib/stax.properties" in the JRE directory.
+   *     This configuration file is in standard java.util.Properties format
+   *     and contains the fully qualified name of the implementation class
+   *     with the key being the given {@code factoryId}.
+   * </li>
+   * <li>
+   *   If {@code factoryId} is "javax.xml.stream.XMLEventFactory",
+   *   use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   *   Otherwise, throws a {@link FactoryConfigurationError}.
+   * </li>
+   * </ul>
    *
+   * <p>
    * Note that this is a new method that replaces the deprecated
-   *   newInstance(String factoryId, ClassLoader classLoader) method.
+   *   {@link #newInstance(java.lang.String, java.lang.ClassLoader)
+   *   newInstance(String factoryId, ClassLoader classLoader)} method.
    * No changes in behavior are defined by this replacement method relative
    * to the deprecated method.
+   * </p>
    *
    * @param factoryId             Name of the factory to find, same as
    *                              a property name
    * @param classLoader           classLoader to use
    * @return the factory implementation
-   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    */
   public static XMLEventFactory newFactory(String factoryId,
-          ClassLoader classLoader)
+                                           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null);
   }
 
  /**
--- a/jaxp/src/javax/xml/stream/XMLInputFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/stream/XMLInputFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -23,13 +23,13 @@
  */
 
 /*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
+ * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
  */
 
 package javax.xml.stream;
 
+import javax.xml.stream.util.XMLEventAllocator;
 import javax.xml.transform.Source;
-import javax.xml.stream.util.XMLEventAllocator;
 
 /**
  * Defines an abstract implementation of a factory for getting streams.
@@ -144,48 +144,59 @@
   protected XMLInputFactory(){}
 
   /**
-   * Create a new instance of the factory.
+   * Creates a new instance of the factory in exactly the same manner as the
+   * {@link #newFactory()} method.
    * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
    */
   public static XMLInputFactory newInstance()
     throws FactoryConfigurationError
   {
-    return (XMLInputFactory) FactoryFinder.find(
-      "javax.xml.stream.XMLInputFactory",
-      DEFAULIMPL);
+    return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL);
   }
 
   /**
    * Create a new instance of the factory.
+   * <p>
    * This static method creates a new factory instance.
    * This method uses the following ordered lookup procedure to determine
    * the XMLInputFactory implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
    *   Use the javax.xml.stream.XMLInputFactory system property.
+   * </li>
+   * <li>
    *   Use the properties file "lib/stax.properties" in the JRE directory.
    *     This configuration file is in standard java.util.Properties format
    *     and contains the fully qualified name of the implementation class
    *     with the key being the system property defined above.
-   *   Use the Services API (as detailed in the JAR specification), if available,
-   *     to determine the classname. The Services API will look for a classname
-   *     in the file META-INF/services/javax.xml.stream.XMLInputFactory in jars
-   *     available to the runtime.
-   *   Platform default XMLInputFactory instance.
-   *
+   * </li>
+   * <li>
+   *   Use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   * Otherwise, the system-default implementation is returned.
+   * </li>
+   * </ul>
+   * <p>
    *   Once an application has obtained a reference to a XMLInputFactory it
    *   can use the factory to configure and obtain stream instances.
-   *
+   * </p>
+   * <p>
    *   Note that this is a new method that replaces the deprecated newInstance() method.
    *     No changes in behavior are defined by this replacement method relative to
    *     the deprecated method.
-   *
-   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
+   * </p>
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    */
   public static XMLInputFactory newFactory()
     throws FactoryConfigurationError
   {
-    return (XMLInputFactory) FactoryFinder.find(
-      "javax.xml.stream.XMLInputFactory",
-      DEFAULIMPL);
+    return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL);
   }
 
   /**
@@ -206,40 +217,60 @@
   public static XMLInputFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
   }
 
   /**
    * Create a new instance of the factory.
    * If the classLoader argument is null, then the ContextClassLoader is used.
+   * <p>
+   * This method uses the following ordered lookup procedure to determine
+   * the XMLInputFactory implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
+   *   Use the value of the system property identified by {@code factoryId}.
+   * </li>
+   * <li>
+   *   Use the properties file "lib/stax.properties" in the JRE directory.
+   *     This configuration file is in standard java.util.Properties format
+   *     and contains the fully qualified name of the implementation class
+   *     with the key being the given {@code factoryId}.
+   * </li>
+   * <li>
+   *   If {@code factoryId} is "javax.xml.stream.XMLInputFactory",
+   *   use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   *   Otherwise, throws a {@link FactoryConfigurationError}.
+   * </li>
+   * </ul>
    *
+   * <p>
    * Note that this is a new method that replaces the deprecated
-   *   newInstance(String factoryId, ClassLoader classLoader) method.
+   *   {@link #newInstance(java.lang.String, java.lang.ClassLoader)
+   *   newInstance(String factoryId, ClassLoader classLoader)} method.
    * No changes in behavior are defined by this replacement method relative
    * to the deprecated method.
+   * </p>
    *
    * @param factoryId             Name of the factory to find, same as
    *                              a property name
    * @param classLoader           classLoader to use
    * @return the factory implementation
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
    */
   public static XMLInputFactory newFactory(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
   }
 
   /**
--- a/jaxp/src/javax/xml/stream/XMLOutputFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/stream/XMLOutputFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -23,7 +23,7 @@
  */
 
 /*
- * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved.
+ * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved.
  */
 
 package javax.xml.stream;
@@ -120,46 +120,58 @@
   protected XMLOutputFactory(){}
 
   /**
-   * Create a new instance of the factory.
+   * Creates a new instance of the factory in exactly the same manner as the
+   * {@link #newFactory()} method.
    * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
    */
   public static XMLOutputFactory newInstance()
     throws FactoryConfigurationError
   {
-    return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory",
-                                                 DEFAULIMPL);
+    return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
   }
 
   /**
    * Create a new instance of the factory.
+   * <p>
    * This static method creates a new factory instance. This method uses the
    * following ordered lookup procedure to determine the XMLOutputFactory
    * implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
    *   Use the javax.xml.stream.XMLOutputFactory system property.
+   * </li>
+   * <li>
    *   Use the properties file "lib/stax.properties" in the JRE directory.
    *     This configuration file is in standard java.util.Properties format
    *     and contains the fully qualified name of the implementation class
    *     with the key being the system property defined above.
-   *   Use the Services API (as detailed in the JAR specification), if available,
-   *     to determine the classname. The Services API will look for a classname
-   *     in the file META-INF/services/javax.xml.stream.XMLOutputFactory in jars
-   *     available to the runtime.
-   *   Platform default XMLOutputFactory instance.
-   *
+   * </li>
+   * <li>
+   *   Use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   *   Otherwise, the system-default implementation is returned.
+   * </li>
+   * <p>
    * Once an application has obtained a reference to a XMLOutputFactory it
    * can use the factory to configure and obtain stream instances.
-   *
+   * </p>
+   * <p>
    * Note that this is a new method that replaces the deprecated newInstance() method.
    *   No changes in behavior are defined by this replacement method relative to the
    *   deprecated method.
-   *
-   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
+   * </p>
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    */
   public static XMLOutputFactory newFactory()
     throws FactoryConfigurationError
   {
-    return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory",
-                                                 DEFAULIMPL);
+    return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL);
   }
 
   /**
@@ -179,42 +191,59 @@
   public static XMLInputFactory newInstance(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null);
   }
 
   /**
    * Create a new instance of the factory.
    * If the classLoader argument is null, then the ContextClassLoader is used.
-   *
-   * Note that this is a new method that replaces the deprecated
-   *   newInstance(String factoryId, ClassLoader classLoader) method.
+   * <p>
+   * This method uses the following ordered lookup procedure to determine
+   * the XMLOutputFactory implementation class to load:
+   * </p>
+   * <ul>
+   * <li>
+   *   Use the value of the system property identified by {@code factoryId}.
+   * </li>
+   * <li>
+   *   Use the properties file "lib/stax.properties" in the JRE directory.
+   *     This configuration file is in standard java.util.Properties format
+   *     and contains the fully qualified name of the implementation class
+   *     with the key being the given {@code factoryId}.
+   * </li>
+   * <li>
+   *   If {@code factoryId} is "javax.xml.stream.XMLOutputFactory",
+   *   use the service-provider loading facilities, defined by the
+   *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+   *   implementation of the service.
+   * </li>
+   * <li>
+   *   Otherwise, throws a {@link FactoryConfigurationError}.
+   * </li>
+   * </ul>
    *
-   *   No changes in behavior are defined by this replacement method relative
-   *   to the deprecated method.
-   *
+   * <p>
+   * Note that this is a new method that replaces the deprecated
+   *   {@link #newInstance(java.lang.String, java.lang.ClassLoader)
+   *   newInstance(String factoryId, ClassLoader classLoader)} method.
+   * No changes in behavior are defined by this replacement method relative
+   * to the deprecated method.
+   * </p>
    *
    * @param factoryId             Name of the factory to find, same as
    *                              a property name
    * @param classLoader           classLoader to use
    * @return the factory implementation
-   * @throws FactoryConfigurationError if an instance of this factory cannot be loaded
+   * @throws FactoryConfigurationError in case of {@linkplain
+   *   java.util.ServiceConfigurationError service configuration error} or if
+   *   the implementation is not available or cannot be instantiated.
    */
   public static XMLOutputFactory newFactory(String factoryId,
           ClassLoader classLoader)
           throws FactoryConfigurationError {
-      try {
-          //do not fallback if given classloader can't find the class, throw exception
-          return (XMLOutputFactory) FactoryFinder.find(factoryId, classLoader, null);
-      } catch (FactoryFinder.ConfigurationError e) {
-          throw new FactoryConfigurationError(e.getException(),
-                  e.getMessage());
-      }
+      //do not fallback if given classloader can't find the class, throw exception
+      return FactoryFinder.find(XMLOutputFactory.class, factoryId, classLoader, null);
   }
 
   /**
--- a/jaxp/src/javax/xml/transform/FactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/transform/FactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,15 @@
 
 package javax.xml.transform;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
 import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
  * <p>Implements pluggable Datatypes.</p>
@@ -53,7 +55,7 @@
     /**
      * Cache for properties in java.home/lib/jaxp.properties
      */
-    static Properties cacheProps = new Properties();
+    private final static Properties cacheProps = new Properties();
 
     /**
      * Flag indicating if properties from java.home/lib/jaxp.properties
@@ -65,7 +67,7 @@
      * Security support class use to check access control before
      * getting certain system resources.
      */
-    static SecuritySupport ss = new SecuritySupport();
+    private final static SecuritySupport ss = new SecuritySupport();
 
     // Define system property "jaxp.debug" to get output
     static {
@@ -98,31 +100,31 @@
      *
      * Use bootstrap classLoader if cl = null and useBSClsLoader is true
      */
-    static private Class getProviderClass(String className, ClassLoader cl,
+    static private Class<?> getProviderClass(String className, ClassLoader cl,
             boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException
     {
         try {
             if (cl == null) {
                 if (useBSClsLoader) {
-                    return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                    return Class.forName(className, false, FactoryFinder.class.getClassLoader());
                 } else {
                     cl = ss.getContextClassLoader();
                     if (cl == null) {
                         throw new ClassNotFoundException();
                     }
                     else {
-                        return cl.loadClass(className);
+                        return Class.forName(className, false, cl);
                     }
                 }
             }
             else {
-                return cl.loadClass(className);
+                return Class.forName(className, false, cl);
             }
         }
         catch (ClassNotFoundException e1) {
             if (doFallback) {
                 // Use current class loader - should always be bootstrap CL
-                return Class.forName(className, true, FactoryFinder.class.getClassLoader());
+                return Class.forName(className, false, FactoryFinder.class.getClassLoader());
             }
             else {
                 throw e1;
@@ -134,24 +136,8 @@
      * Create an instance of a class. Delegates to method
      * <code>getProviderClass()</code> in order to load the class.
      *
-     * @param className Name of the concrete class corresponding to the
-     * service provider
-     *
-     * @param cl <code>ClassLoader</code> used to load the factory class. If <code>null</code>
-     * current <code>Thread</code>'s context classLoader is used to load the factory class.
-     *
-     * @param doFallback True if the current ClassLoader should be tried as
-     * a fallback if the class is not found using cl
-     */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback)
-        throws ConfigurationError
-    {
-        return newInstance(className, cl, doFallback, false, false);
-    }
-
-    /**
-     * Create an instance of a class. Delegates to method
-     * <code>getProviderClass()</code> in order to load the class.
+     * @param type Base class / Service interface  of the factory to
+     *             instantiate.
      *
      * @param className Name of the concrete class corresponding to the
      * service provider
@@ -162,14 +148,15 @@
      * @param doFallback True if the current ClassLoader should be tried as
      * a fallback if the class is not found using cl
      *
-     * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter
-     * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader.
-     *
      * @param useServicesMechanism True use services mechanism
      */
-    static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism)
-        throws ConfigurationError
+    static <T> T newInstance(Class<T> type, String className, ClassLoader cl,
+                             boolean doFallback, boolean useServicesMechanism)
+        throws TransformerFactoryConfigurationError
     {
+        assert type != null;
+
+        boolean useBSClsLoader = false;
         // make sure we have access to restricted packages
         if (System.getSecurityManager() != null) {
             if (className != null && className.startsWith(DEFAULT_PACKAGE)) {
@@ -179,10 +166,13 @@
         }
 
         try {
-            Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            Class<?> providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader);
+            if (!type.isAssignableFrom(providerClass)) {
+                throw new ClassCastException(className + " cannot be cast to " + type.getName());
+            }
             Object instance = null;
             if (!useServicesMechanism) {
-                instance = newInstanceNoServiceLoader(providerClass);
+                instance = newInstanceNoServiceLoader(type, providerClass);
             }
             if (instance == null) {
                 instance = providerClass.newInstance();
@@ -191,63 +181,87 @@
                 dPrint("created new instance of " + providerClass +
                        " using ClassLoader: " + cl);
             }
-            return instance;
+            return type.cast(instance);
         }
         catch (ClassNotFoundException x) {
-            throw new ConfigurationError(
-                "Provider " + className + " not found", x);
+            throw new TransformerFactoryConfigurationError(x,
+                "Provider " + className + " not found");
         }
         catch (Exception x) {
-            throw new ConfigurationError(
-                "Provider " + className + " could not be instantiated: " + x,
-                x);
+            throw new TransformerFactoryConfigurationError(x,
+                "Provider " + className + " could not be instantiated: " + x);
         }
     }
+
     /**
      * Try to construct using newTransformerFactoryNoServiceLoader
      *   method if available.
      */
-    private static Object newInstanceNoServiceLoader(
-         Class<?> providerClass
-    ) {
+    private static <T> T newInstanceNoServiceLoader(Class<T> type, Class<?> providerClass) {
         // Retain maximum compatibility if no security manager.
         if (System.getSecurityManager() == null) {
             return null;
         }
         try {
-            Method creationMethod =
-                providerClass.getDeclaredMethod(
-                    "newTransformerFactoryNoServiceLoader"
-                );
-                return creationMethod.invoke(null, (Object[])null);
-            } catch (NoSuchMethodException exc) {
+            final Method creationMethod =
+                    providerClass.getDeclaredMethod(
+                        "newTransformerFactoryNoServiceLoader"
+                    );
+            final int modifiers = creationMethod.getModifiers();
+
+            // Do not call the method if it's not public static.
+            if (!Modifier.isPublic(modifiers) || !Modifier.isStatic(modifiers)) {
                 return null;
-            } catch (Exception exc) {
-                return null;
+            }
+
+            // Only call the method if it's declared to return an instance of
+            // TransformerFactory
+            final Class<?> returnType = creationMethod.getReturnType();
+            if (type.isAssignableFrom(returnType)) {
+                final Object result = creationMethod.invoke(null, (Object[])null);
+                return type.cast(result);
+            } else {
+                // This should not happen, as
+                // TransformerFactoryImpl.newTransformerFactoryNoServiceLoader is
+                // declared to return TransformerFactory.
+                throw new ClassCastException(returnType + " cannot be cast to " + type);
+            }
+        } catch (ClassCastException e) {
+            throw new TransformerFactoryConfigurationError(e, e.getMessage());
+        } catch (NoSuchMethodException exc) {
+            return null;
+        } catch (Exception exc) {
+            return null;
         }
     }
+
     /**
      * Finds the implementation Class object in the specified order.  Main
      * entry point.
      * @return Class object of factory, never null
      *
-     * @param factoryId             Name of the factory to find, same as
-     *                              a property name
+     * @param type                  Base class / Service interface  of the
+     *                              factory to find.
+     *
      * @param fallbackClassName     Implementation class name, if nothing else
      *                              is found.  Use null to mean no fallback.
      *
      * Package private so this code can be shared.
      */
-    static Object find(String factoryId, String fallbackClassName)
-        throws ConfigurationError
+    static <T> T find(Class<T> type, String fallbackClassName)
+        throws TransformerFactoryConfigurationError
     {
+        assert type != null;
+
+        final String factoryId = type.getName();
+
         dPrint("find factoryId =" + factoryId);
         // Use the system property first
         try {
             String systemProp = ss.getSystemProperty(factoryId);
             if (systemProp != null) {
                 dPrint("found system property, value=" + systemProp);
-                return newInstance(systemProp, null, true, false, true);
+                return newInstance(type, systemProp, null, true, true);
             }
         }
         catch (SecurityException se) {
@@ -256,7 +270,6 @@
 
         // try to read from $java.home/lib/jaxp.properties
         try {
-            String factoryClassName = null;
             if (firstTime) {
                 synchronized (cacheProps) {
                     if (firstTime) {
@@ -271,11 +284,11 @@
                     }
                 }
             }
-            factoryClassName = cacheProps.getProperty(factoryId);
+            final String factoryClassName = cacheProps.getProperty(factoryId);
 
             if (factoryClassName != null) {
                 dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName);
-                return newInstance(factoryClassName, null, true, false, true);
+                return newInstance(type, factoryClassName, null, true, true);
             }
         }
         catch (Exception ex) {
@@ -283,113 +296,54 @@
         }
 
         // Try Jar Service Provider Mechanism
-        Object provider = findJarServiceProvider(factoryId);
+        T provider = findServiceProvider(type);
         if (provider != null) {
             return provider;
         }
         if (fallbackClassName == null) {
-            throw new ConfigurationError(
-                "Provider for " + factoryId + " cannot be found", null);
+            throw new TransformerFactoryConfigurationError(null,
+                "Provider for " + factoryId + " cannot be found");
         }
 
         dPrint("loaded from fallback value: " + fallbackClassName);
-        return newInstance(fallbackClassName, null, true, false, true);
+        return newInstance(type, fallbackClassName, null, true, true);
     }
 
     /*
-     * Try to find provider using Jar Service Provider Mechanism
+     * Try to find provider using the ServiceLoader.
+     *
+     * @param type Base class / Service interface  of the factory to find.
      *
      * @return instance of provider class if found or null
      */
-    private static Object findJarServiceProvider(String factoryId)
-        throws ConfigurationError
+    private static <T> T findServiceProvider(final Class<T> type)
+        throws TransformerFactoryConfigurationError
     {
-        String serviceId = "META-INF/services/" + factoryId;
-        InputStream is = null;
-
-        // First try the Context ClassLoader
-        ClassLoader cl = ss.getContextClassLoader();
-        boolean useBSClsLoader = false;
-        if (cl != null) {
-            is = ss.getResourceAsStream(cl, serviceId);
-
-            // If no provider found then try the current ClassLoader
-            if (is == null) {
-                cl = FactoryFinder.class.getClassLoader();
-                is = ss.getResourceAsStream(cl, serviceId);
-                useBSClsLoader = true;
-           }
-        } else {
-            // No Context ClassLoader, try the current ClassLoader
-            cl = FactoryFinder.class.getClassLoader();
-            is = ss.getResourceAsStream(cl, serviceId);
-            useBSClsLoader = true;
-        }
-
-        if (is == null) {
-            // No provider found
-            return null;
-        }
-
-        if (debug) {    // Extra check to avoid computing cl strings
-            dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl);
-        }
-
-        BufferedReader rd;
-        try {
-            rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-        }
-        catch (java.io.UnsupportedEncodingException e) {
-            rd = new BufferedReader(new InputStreamReader(is));
-        }
-
-        String factoryClassName = null;
-        try {
-            // XXX Does not handle all possible input as specified by the
-            // Jar Service Provider specification
-            factoryClassName = rd.readLine();
-            rd.close();
-        } catch (IOException x) {
-            // No provider found
-            return null;
-        }
-
-        if (factoryClassName != null && !"".equals(factoryClassName)) {
-            dPrint("found in resource, value=" + factoryClassName);
-
-            // Note: here we do not want to fall back to the current
-            // ClassLoader because we want to avoid the case where the
-            // resource file was found using one ClassLoader and the
-            // provider class was instantiated using a different one.
-            return newInstance(factoryClassName, cl, false, useBSClsLoader, true);
-        }
-
-        // No provider found
-        return null;
-    }
-
-    static class ConfigurationError extends Error {
-        private Exception exception;
-
-        /**
-         * Construct a new instance with the specified detail string and
-         * exception.
-         */
-        ConfigurationError(String msg, Exception x) {
-            super(msg);
-            this.exception = x;
-        }
-
-        Exception getException() {
-            return exception;
-        }
-        /**
-        * use the exception chaining mechanism of JDK1.4
-        */
-        @Override
-        public Throwable getCause() {
-            return exception;
+      try {
+            return AccessController.doPrivileged(new PrivilegedAction<T>() {
+                public T run() {
+                    final ServiceLoader<T> serviceLoader = ServiceLoader.load(type);
+                    final Iterator<T> iterator = serviceLoader.iterator();
+                    if (iterator.hasNext()) {
+                        return iterator.next();
+                    } else {
+                        return null;
+                    }
+                 }
+            });
+        } catch(ServiceConfigurationError e) {
+            // It is not possible to wrap an error directly in
+            // FactoryConfigurationError - so we need to wrap the
+            // ServiceConfigurationError in a RuntimeException.
+            // The alternative would be to modify the logic in
+            // FactoryConfigurationError to allow setting a
+            // Throwable as the cause, but that could cause
+            // compatibility issues down the road.
+            final RuntimeException x = new RuntimeException(
+                    "Provider for " + type + " cannot be created", e);
+            final TransformerFactoryConfigurationError error =
+                    new TransformerFactoryConfigurationError(x, x.getMessage());
+            throw error;
         }
     }
-
 }
--- a/jaxp/src/javax/xml/transform/TransformerFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/transform/TransformerFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,8 +52,8 @@
 
     /**
      * <p>Obtain a new instance of a <code>TransformerFactory</code>.
-     * This static method creates a new factory instance
-     * This method uses the following ordered lookup procedure to determine
+     * This static method creates a new factory instance.</p>
+     * <p>This method uses the following ordered lookup procedure to determine
      * the <code>TransformerFactory</code> implementation class to
      * load:</p>
      * <ul>
@@ -67,7 +67,7 @@
      * </code> format and contains the fully qualified name of the
      * implementation class with the key being the system property defined
      * above.
-     *
+     * <br>
      * The jaxp.properties file is read only once by the JAXP implementation
      * and it's values are then cached for future use.  If the file does not exist
      * when the first attempt is made to read from it, no further attempts are
@@ -75,14 +75,12 @@
      * of any property in jaxp.properties after it has been read for the first time.
      * </li>
      * <li>
-     * Use the Services API (as detailed in the JAR specification), if
-     * available, to determine the classname. The Services API will look
-     * for a classname in the file
-     * <code>META-INF/services/javax.xml.transform.TransformerFactory</code>
-     * in jars available to the runtime.
+     *   Use the service-provider loading facilities, defined by the
+     *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+     *   implementation of the service.
      * </li>
      * <li>
-     * Platform default <code>TransformerFactory</code> instance.
+     *   Otherwise, the system-default implementation is returned.
      * </li>
      * </ul>
      *
@@ -92,22 +90,18 @@
      *
      * @return new TransformerFactory instance, never null.
      *
-     * @throws TransformerFactoryConfigurationError Thrown if the implementation
-     *    is not available or cannot be instantiated.
+     * @throws TransformerFactoryConfigurationError Thrown in case of {@linkplain
+     * java.util.ServiceConfigurationError service configuration error} or if
+     * the implementation is not available or cannot be instantiated.
      */
     public static TransformerFactory newInstance()
         throws TransformerFactoryConfigurationError {
-        try {
-            return (TransformerFactory) FactoryFinder.find(
+
+        return FactoryFinder.find(
             /* The default property name according to the JAXP spec */
-            "javax.xml.transform.TransformerFactory",
+            TransformerFactory.class,
             /* The fallback implementation class name, XSLTC */
             "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new TransformerFactoryConfigurationError(
-                e.getException(),
-                e.getMessage());
-        }
     }
 
     /**
@@ -147,14 +141,10 @@
      */
     public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader)
         throws TransformerFactoryConfigurationError{
-        try {
-            //do not fallback if given classloader can't find the class, throw exception
-            return (TransformerFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false);
-        } catch (FactoryFinder.ConfigurationError e) {
-            throw new TransformerFactoryConfigurationError(
-                e.getException(),
-                e.getMessage());
-        }
+
+        //do not fallback if given classloader can't find the class, throw exception
+        return  FactoryFinder.newInstance(TransformerFactory.class,
+                    factoryClassName, classLoader, false, false);
     }
     /**
      * <p>Process the <code>Source</code> into a <code>Transformer</code>
--- a/jaxp/src/javax/xml/validation/SchemaFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/validation/SchemaFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,15 +27,14 @@
 
 import java.io.File;
 import java.net.URL;
-
 import javax.xml.transform.Source;
 import javax.xml.transform.stream.StreamSource;
-
 import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.ErrorHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXNotRecognizedException;
 import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
 
 /**
  * Factory that creates {@link Schema} objects&#x2E; Entry-point to
@@ -79,7 +78,7 @@
  * and has a significant effect on the parsing process, it is impossible
  * to define the DTD validation as a process independent from parsing.
  * For this reason, this specification does not define the semantics for
- * the XML DTD. This doesn't prohibit implentors from implementing it
+ * the XML DTD. This doesn't prohibit implementors from implementing it
  * in a way they see fit, but <em>users are warned that any DTD
  * validation implemented on this interface necessarily deviate from
  * the XML DTD semantics as defined in the XML 1.0</em>.
@@ -147,14 +146,17 @@
      *     is looked for. If present, the value is processed just like above.
      *   </li>
      *   <li>
-     *     <p>The class loader is asked for service provider provider-configuration files matching
-     *     <code>javax.xml.validation.SchemaFactory</code> in the resource directory META-INF/services.
-     *     See the JAR File Specification for file format and parsing rules.
-     *     Each potential service provider is required to implement the method:</p>
-     *     <pre>
-     *        {@link #isSchemaLanguageSupported(String schemaLanguage)}
-     *     </pre>
-     *     The first service provider found in class loader order that supports the specified schema language is returned.
+     *   Use the service-provider loading facilities, defined by the
+     *   {@link java.util.ServiceLoader} class, to attempt to locate and load an
+     *   implementation of the service.<br>
+     *   Each potential service provider is required to implement the method
+     *        {@link #isSchemaLanguageSupported(String schemaLanguage)}.
+     *   <br>
+     *   The first service provider found that supports the specified schema
+     *   language is returned.
+     *   <br>
+     *   In case of {@link java.util.ServiceConfigurationError} a
+     *   {@link SchemaFactoryConfigurationError} will be thrown.
      *   </li>
      *   <li>
      *     Platform default <code>SchemaFactory</code> is located
@@ -186,10 +188,12 @@
      *      If no implementation of the schema language is available.
      * @throws NullPointerException
      *      If the <code>schemaLanguage</code> parameter is null.
+     * @throws SchemaFactoryConfigurationError
+     *      If a configuration error is encountered.
      *
      * @see #newInstance(String schemaLanguage, String factoryClassName, ClassLoader classLoader)
      */
-    public static final SchemaFactory newInstance(String schemaLanguage) {
+    public static SchemaFactory newInstance(String schemaLanguage) {
         ClassLoader cl;
         cl = ss.getContextClassLoader();
 
@@ -275,19 +279,19 @@
 
     }
 
-        /**
-         * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
-         *
-         * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
+    /**
+     * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
+     *
+     * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
      *    <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
-         *
-         * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
-         *
-         * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
-         * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
-         *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
-         */
-        public abstract boolean isSchemaLanguageSupported(String schemaLanguage);
+     *
+     * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
+     *
+     * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
+     * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
+     *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
+     */
+    public abstract boolean isSchemaLanguageSupported(String schemaLanguage);
 
     /**
      * Look up the value of a feature flag.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.xml.validation;
+
+/**
+ * Thrown when a problem with configuration with the Schema Factories
+ * exists. This error will typically be thrown when the class of a
+ * schema factory specified in the system properties cannot be found
+ * or instantiated.
+ * @since 1.8
+ */
+public final class SchemaFactoryConfigurationError extends Error {
+
+    static final long serialVersionUID = 3531438703147750126L;
+
+    /**
+     * Create a new <code>SchemaFactoryConfigurationError</code> with no
+     * detail message.
+     */
+    public SchemaFactoryConfigurationError() {
+    }
+
+
+    /**
+     * Create a new <code>SchemaFactoryConfigurationError</code> with
+     * the <code>String</code> specified as an error message.
+     *
+     * @param message The error message for the exception.
+     */
+    public SchemaFactoryConfigurationError(String message) {
+        super(message);
+    }
+
+    /**
+     * Create a new <code>SchemaFactoryConfigurationError</code> with the
+     * given <code>Throwable</code> base cause.
+     *
+     * @param cause The exception or error to be encapsulated in a
+     * SchemaFactoryConfigurationError.
+     */
+    public SchemaFactoryConfigurationError(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Create a new <code>SchemaFactoryConfigurationError</code> with the
+     * given <code>Throwable</code> base cause and detail message.
+     *
+     * @param cause The exception or error to be encapsulated in a
+     * SchemaFactoryConfigurationError.
+     * @param message The detail message.
+     */
+    public SchemaFactoryConfigurationError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
--- a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,19 +25,16 @@
 
 package javax.xml.validation;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
  * Implementation of {@link SchemaFactory#newInstance(String)}.
@@ -53,17 +50,17 @@
     /**
      *<p> Take care of restrictions imposed by java security model </p>
      */
-    private static SecuritySupport ss = new SecuritySupport();
+    private static final SecuritySupport ss = new SecuritySupport();
     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal";
     /**
      * <p>Cache properties for performance.</p>
      */
-        private static Properties cacheProps = new Properties();
+    private static final Properties cacheProps = new Properties();
 
-        /**
-         * <p>First time requires initialization overhead.</p>
-         */
-        private static volatile boolean firstTime = true;
+    /**
+     * <p>First time requires initialization overhead.</p>
+     */
+    private static volatile boolean firstTime = true;
 
     static {
         // Use try/catch block to support applets
@@ -115,7 +112,7 @@
                 return;
             }
         } catch( Throwable unused ) {
-            ; // getContextClassLoader() undefined in JDK1.1
+            // getContextClassLoader() undefined in JDK1.1
         }
 
         if( classLoader==ClassLoader.getSystemClassLoader() ) {
@@ -138,9 +135,13 @@
      *
      * @throws NullPointerException
      *      If the <code>schemaLanguage</code> parameter is null.
+     * @throws SchemaFactoryConfigurationError
+     *      If a configuration error is encountered.
      */
     public SchemaFactory newFactory(String schemaLanguage) {
-        if(schemaLanguage==null)        throw new NullPointerException();
+        if(schemaLanguage==null) {
+            throw new NullPointerException();
+        }
         SchemaFactory f = _newFactory(schemaLanguage);
         if (f != null) {
             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage);
@@ -183,7 +184,6 @@
         String configFile = javah + File.separator +
         "lib" + File.separator + "jaxp.properties";
 
-        String factoryClassName = null ;
 
         // try to read from $java.home/lib/jaxp.properties
         try {
@@ -199,7 +199,7 @@
                     }
                 }
             }
-            factoryClassName = cacheProps.getProperty(propertyName);
+            final String factoryClassName = cacheProps.getProperty(propertyName);
             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
 
             if (factoryClassName != null) {
@@ -214,21 +214,15 @@
             }
         }
 
-        // try META-INF/services files
-        Iterator sitr = createServiceFileIterator();
-        while(sitr.hasNext()) {
-            URL resource = (URL)sitr.next();
-            debugPrintln("looking into " + resource);
-            try {
-                sf = loadFromService(schemaLanguage,resource.toExternalForm(),
-                                                ss.getURLInputStream(resource));
-                if(sf!=null)    return sf;
-            } catch(IOException e) {
-                if( debug ) {
-                    debugPrintln("failed to read "+resource);
-                    e.printStackTrace();
-                }
-            }
+        // Try with ServiceLoader
+        final SchemaFactory factoryImpl = findServiceProvider(schemaLanguage);
+
+        // The following assertion should always be true.
+        // Uncomment it, recompile, and run with -ea in case of doubts:
+        // assert factoryImpl == null || factoryImpl.isSchemaLanguageSupported(schemaLanguage);
+
+        if (factoryImpl != null) {
+            return factoryImpl;
         }
 
         // platform default
@@ -246,8 +240,8 @@
      * @param className Name of class to create.
      * @return Created class or <code>null</code>.
      */
-    private Class createClass(String className) {
-            Class clazz;
+    private Class<?> createClass(String className) {
+        Class<?> clazz;
         // make sure we have access to restricted packages
         boolean internal = false;
         if (System.getSecurityManager() != null) {
@@ -256,25 +250,27 @@
             }
         }
 
-            try {
-                if (classLoader != null && !internal) {
-                        clazz = classLoader.loadClass(className);
-                } else {
-                        clazz = Class.forName(className);
-                }
-            } catch (Throwable t) {
-                if(debug)   t.printStackTrace();
-                    return null;
+        try {
+            if (classLoader != null && !internal) {
+                clazz = Class.forName(className, false, classLoader);
+            } else {
+                clazz = Class.forName(className);
             }
+        } catch (Throwable t) {
+            if(debug)  {
+                t.printStackTrace();
+            }
+            return null;
+        }
 
-            return clazz;
+        return clazz;
     }
 
     /**
      * <p>Creates an instance of the specified and returns it.</p>
      *
      * @param className
-     *      fully qualified class name to be instanciated.
+     *      fully qualified class name to be instantiated.
      *
      * @return null
      *      if it fails. Error messages will be printed by this method.
@@ -289,7 +285,7 @@
         debugPrintln("createInstance(" + className + ")");
 
         // get Class from className
-        Class clazz = createClass(className);
+        Class<?> clazz = createClass(className);
         if (clazz == null) {
                 debugPrintln("failed to getClass(" + className + ")");
                 return null;
@@ -298,9 +294,13 @@
 
         // instantiate Class as a SchemaFactory
         try {
-            if (!useServicesMechanism) {
-                schemaFactory = (SchemaFactory) newInstanceNoServiceLoader(clazz);
-            }
+                if (!SchemaFactory.class.isAssignableFrom(clazz)) {
+                    throw new ClassCastException(clazz.getName()
+                                + " cannot be cast to " + SchemaFactory.class);
+                }
+                if (!useServicesMechanism) {
+                    schemaFactory = newInstanceNoServiceLoader(clazz);
+                }
                 if (schemaFactory == null) {
                     schemaFactory = (SchemaFactory) clazz.newInstance();
                 }
@@ -326,11 +326,12 @@
 
         return schemaFactory;
     }
+
     /**
-     * Try to construct using newTransformerFactoryNoServiceLoader
+     * Try to construct using newXMLSchemaFactoryNoServiceLoader
      *   method if available.
      */
-    private static Object newInstanceNoServiceLoader(
+    private static SchemaFactory newInstanceNoServiceLoader(
          Class<?> providerClass
     ) {
         // Retain maximum compatibility if no security manager.
@@ -338,196 +339,87 @@
             return null;
         }
         try {
-            Method creationMethod =
+            final Method creationMethod =
                 providerClass.getDeclaredMethod(
                     "newXMLSchemaFactoryNoServiceLoader"
                 );
-                return creationMethod.invoke(null, (Object[])null);
-            } catch (NoSuchMethodException exc) {
-                return null;
-            } catch (Exception exc) {
-                return null;
-        }
-    }
+            final int modifiers = creationMethod.getModifiers();
 
-    /** Iterator that lazily computes one value and returns it. */
-    private static abstract class SingleIterator implements Iterator {
-        private boolean seen = false;
-
-        public final void remove() { throw new UnsupportedOperationException(); }
-        public final boolean hasNext() { return !seen; }
-        public final Object next() {
-            if(seen)    throw new NoSuchElementException();
-            seen = true;
-            return value();
-        }
+            // Do not call the method if it's not public static.
+            if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
+                return null;
+            }
 
-        protected abstract Object value();
-    }
-
-    /**
-     * Looks up a value in a property file
-     * while producing all sorts of debug messages.
-     *
-     * @return null
-     *      if there was an error.
-     */
-    private SchemaFactory loadFromProperty( String keyName, String resourceName, InputStream in )
-        throws IOException {
-        debugPrintln("Reading "+resourceName );
-
-        Properties props=new Properties();
-        props.load(in);
-        in.close();
-        String factoryClassName = props.getProperty(keyName);
-        if(factoryClassName != null){
-            debugPrintln("found "+keyName+" = " + factoryClassName);
-            return createInstance(factoryClassName);
-        } else {
-            debugPrintln(keyName+" is not in the property file");
+            // Only calls "newXMLSchemaFactoryNoServiceLoader" if it's
+            // declared to return an instance of SchemaFactory.
+            final Class<?> returnType = creationMethod.getReturnType();
+            if (SERVICE_CLASS.isAssignableFrom(returnType)) {
+                return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
+            } else {
+                // Should not happen since
+                // XMLSchemaFactory.newXMLSchemaFactoryNoServiceLoader is
+                // declared to return XMLSchemaFactory.
+                throw new ClassCastException(returnType
+                            + " cannot be cast to " + SERVICE_CLASS);
+            }
+        } catch(ClassCastException e) {
+            throw new SchemaFactoryConfigurationError(e.getMessage(), e);
+        } catch (NoSuchMethodException exc) {
+            return null;
+        } catch (Exception exc) {
             return null;
         }
     }
 
-    /**
-     * <p>Look up a value in a property file.</p>
-     *
-     * <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
-     *
-     * @param schemaLanguage Schema Language to support.
-     * @param inputName Name of <code>InputStream</code>.
-     * @param in <code>InputStream</code> of properties.
-     *
-     * @return <code>SchemaFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
-     *
-     * @throws IOException If IO error reading from <code>in</code>.
-     */
-    private SchemaFactory loadFromService(
-            String schemaLanguage,
-            String inputName,
-            InputStream in)
-            throws IOException {
-
-            SchemaFactory schemaFactory = null;
-            final Class[] stringClassArray = {"".getClass()};
-            final Object[] schemaLanguageObjectArray = {schemaLanguage};
-            final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported";
-
-            debugPrintln("Reading " + inputName);
-
-            // read from InputStream until a match is found
-            BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
-            String line = null;
-            while ((line = configFile.readLine()) != null) {
-                    // '#' is comment char
-                    int comment = line.indexOf("#");
-                    switch (comment) {
-                            case -1: break; // no comment
-                            case 0: line = ""; break; // entire line is a comment
-                            default: line = line.substring(0, comment); break; // trim comment
-                    }
-
-                    // trim whitespace
-                    line = line.trim();
-
-                    // any content left on line?
-                    if (line.length() == 0) {
-                            continue;
-                    }
-
-                    // line content is now the name of the class
-                    Class clazz = createClass(line);
-                    if (clazz == null) {
-                            continue;
-                    }
-
-                    // create an instance of the Class
-                    try {
-                            schemaFactory = (SchemaFactory) clazz.newInstance();
-                    } catch (ClassCastException classCastExcpetion) {
-                            schemaFactory = null;
-                            continue;
-                    } catch (InstantiationException instantiationException) {
-                            schemaFactory = null;
-                            continue;
-                    } catch (IllegalAccessException illegalAccessException) {
-                            schemaFactory = null;
-                            continue;
-                    }
-
-                    // does this Class support desired Schema?
-                    try {
-                            Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray);
-                            Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray);
-                            if (supported.booleanValue()) {
-                                    break;
-                            }
-                    } catch (NoSuchMethodException noSuchMethodException) {
-
-                    } catch (IllegalAccessException illegalAccessException) {
-
-                    } catch (InvocationTargetException invocationTargetException) {
-
-                    }
-                    schemaFactory = null;
+    // Call isSchemaLanguageSupported with initial context.
+    private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory,
+            final String schemaLanguage,
+            AccessControlContext acc) {
+        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+            public Boolean run() {
+                return factory.isSchemaLanguageSupported(schemaLanguage);
             }
-
-            // clean up
-            configFile.close();
-
-            // return new instance of SchemaFactory or null
-            return schemaFactory;
+        }, acc);
     }
 
     /**
-     * Returns an {@link Iterator} that enumerates all
-     * the META-INF/services files that we care.
+     * Finds a service provider subclass of SchemaFactory that supports the
+     * given schema language using the ServiceLoader.
+     *
+     * @param schemaLanguage The schema language for which we seek a factory.
+     * @return A SchemaFactory supporting the specified schema language, or null
+     *         if none is found.
+     * @throws SchemaFactoryConfigurationError if a configuration error is found.
      */
-    private Iterator createServiceFileIterator() {
-        if (classLoader == null) {
-            return new SingleIterator() {
-                protected Object value() {
-                    ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader();
-                    //return (ClassLoader.getSystemResource( SERVICE_ID ));
-                    return ss.getResourceAsURL(classLoader, SERVICE_ID);
-                }
-            };
-        } else {
-            try {
-                //final Enumeration e = classLoader.getResources(SERVICE_ID);
-                final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
-                if(!e.hasMoreElements()) {
-                    debugPrintln("no "+SERVICE_ID+" file was found");
+    private SchemaFactory findServiceProvider(final String schemaLanguage) {
+        assert schemaLanguage != null;
+        // store current context.
+        final AccessControlContext acc = AccessController.getContext();
+        try {
+            return AccessController.doPrivileged(new PrivilegedAction<SchemaFactory>() {
+                public SchemaFactory run() {
+                    final ServiceLoader<SchemaFactory> loader =
+                            ServiceLoader.load(SERVICE_CLASS);
+                    for (SchemaFactory factory : loader) {
+                        // restore initial context to call
+                        // factory.isSchemaLanguageSupported
+                        if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) {
+                            return factory;
+                        }
+                    }
+                    return null; // no factory found.
                 }
-
-                // wrap it into an Iterator.
-                return new Iterator() {
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public boolean hasNext() {
-                        return e.hasMoreElements();
-                    }
-
-                    public Object next() {
-                        return e.nextElement();
-                    }
-                };
-            } catch (IOException e) {
-                debugPrintln("failed to enumerate resources "+SERVICE_ID);
-                if(debug)   e.printStackTrace();
-                return new ArrayList().iterator();  // empty iterator
-            }
+            });
+        } catch (ServiceConfigurationError error) {
+            throw new SchemaFactoryConfigurationError(
+                    "Provider for " + SERVICE_CLASS + " cannot be created", error);
         }
     }
 
-    private static final Class SERVICE_CLASS = SchemaFactory.class;
-    private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
+    private static final Class<SchemaFactory> SERVICE_CLASS = SchemaFactory.class;
 
 
-
-    private static String which( Class clazz ) {
+    private static String which( Class<?> clazz ) {
         return which( clazz.getName(), clazz.getClassLoader() );
     }
 
--- a/jaxp/src/javax/xml/xpath/XPathFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/xpath/XPathFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -90,7 +90,7 @@
      * @throws RuntimeException When there is a failure in creating an
      *   <code>XPathFactory</code> for the default object model.
      */
-    public static final XPathFactory newInstance() {
+    public static XPathFactory newInstance() {
 
         try {
                 return newInstance(DEFAULT_OBJECT_MODEL_URI);
@@ -121,14 +121,17 @@
     *     If present, the value is processed just like above.
     *   </li>
     *   <li>
-    *     The class loader is asked for service provider provider-configuration files matching <code>javax.xml.xpath.XPathFactory</code>
-    *     in the resource directory META-INF/services.
-    *     See the JAR File Specification for file format and parsing rules.
-    *     Each potential service provider is required to implement the method:
-    *     <pre>
-    *       {@link #isObjectModelSupported(String objectModel)}
-    *     </pre>
-    *     The first service provider found in class loader order that supports the specified object model is returned.
+    *     Use the service-provider loading facilities, defined by the
+    *     {@link java.util.ServiceLoader} class, to attempt to locate and load an
+    *     implementation of the service.
+    *     <br>
+    *     Each potential service provider is required to implement the method
+    *     {@link #isObjectModelSupported(String objectModel)}.
+    *     The first service provider found that supports the specified object
+    *     model is returned.
+    *     <br>
+    *     In case of {@link java.util.ServiceConfigurationError} an
+    *     {@link XPathFactoryConfigurationException} will be thrown.
     *   </li>
     *   <li>
     *     Platform default <code>XPathFactory</code> is located in a platform specific way.
@@ -152,43 +155,41 @@
     *
     * @return Instance of an <code>XPathFactory</code>.
     *
-    * @throws XPathFactoryConfigurationException If the specified object model is unavailable.
+    * @throws XPathFactoryConfigurationException If the specified object model
+    *      is unavailable, or if there is a configuration error.
     * @throws NullPointerException If <code>uri</code> is <code>null</code>.
-        * @throws IllegalArgumentException If <code>uri</code> is <code>null</code>
+    * @throws IllegalArgumentException If <code>uri</code> is <code>null</code>
     *   or <code>uri.length() == 0</code>.
     */
-    public static final XPathFactory newInstance(final String uri)
+    public static XPathFactory newInstance(final String uri)
         throws XPathFactoryConfigurationException {
 
         if (uri == null) {
-                throw new NullPointerException(
-                        "XPathFactory#newInstance(String uri) cannot be called with uri == null"
-                );
+            throw new NullPointerException(
+                    "XPathFactory#newInstance(String uri) cannot be called with uri == null");
         }
 
-                if (uri.length() == 0) {
-                        throw new IllegalArgumentException(
-                                "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
-                        );
-                }
+        if (uri.length() == 0) {
+            throw new IllegalArgumentException(
+                    "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"");
+        }
 
-                ClassLoader classLoader = ss.getContextClassLoader();
+        ClassLoader classLoader = ss.getContextClassLoader();
 
         if (classLoader == null) {
             //use the current class loader
             classLoader = XPathFactory.class.getClassLoader();
         }
 
-                XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
+        XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri);
 
-                if (xpathFactory == null) {
-                        throw new XPathFactoryConfigurationException(
-                                "No XPathFactory implementation found for the object model: "
-                                + uri
-                        );
-                }
+        if (xpathFactory == null) {
+            throw new XPathFactoryConfigurationException(
+                    "No XPathFactory implementation found for the object model: "
+                    + uri);
+        }
 
-                return xpathFactory;
+        return xpathFactory;
     }
 
     /**
@@ -242,16 +243,14 @@
         ClassLoader cl = classLoader;
 
         if (uri == null) {
-                throw new NullPointerException(
-                        "XPathFactory#newInstance(String uri) cannot be called with uri == null"
-                );
+            throw new NullPointerException(
+                    "XPathFactory#newInstance(String uri) cannot be called with uri == null");
         }
 
-                if (uri.length() == 0) {
-                        throw new IllegalArgumentException(
-                                "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""
-                        );
-                }
+        if (uri.length() == 0) {
+            throw new IllegalArgumentException(
+                    "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"");
+        }
 
         if (cl == null) {
             cl = ss.getContextClassLoader();
@@ -260,31 +259,32 @@
         XPathFactory f = new XPathFactoryFinder(cl).createInstance(factoryClassName);
 
         if (f == null) {
-                        throw new XPathFactoryConfigurationException(
-                                "No XPathFactory implementation found for the object model: "
-                                + uri
-                        );
+            throw new XPathFactoryConfigurationException(
+                    "No XPathFactory implementation found for the object model: "
+                    + uri);
         }
         //if this factory supports the given schemalanguage return this factory else thrown exception
-        if(f.isObjectModelSupported(uri)){
+        if (f.isObjectModelSupported(uri)) {
             return f;
-        }else{
-            throw new XPathFactoryConfigurationException("Factory " + factoryClassName + " doesn't support given " + uri + " object model");
+        } else {
+            throw new XPathFactoryConfigurationException("Factory "
+                    + factoryClassName + " doesn't support given " + uri
+                    + " object model");
         }
 
     }
 
-        /**
-         * <p>Is specified object model supported by this <code>XPathFactory</code>?</p>
-         *
-         * @param objectModel Specifies the object model which the returned <code>XPathFactory</code> will understand.
-         *
-         * @return <code>true</code> if <code>XPathFactory</code> supports <code>objectModel</code>, else <code>false</code>.
-         *
-         * @throws NullPointerException If <code>objectModel</code> is <code>null</code>.
-         * @throws IllegalArgumentException If <code>objectModel.length() == 0</code>.
-         */
-        public abstract boolean isObjectModelSupported(String objectModel);
+    /**
+     * <p>Is specified object model supported by this <code>XPathFactory</code>?</p>
+     *
+     * @param objectModel Specifies the object model which the returned <code>XPathFactory</code> will understand.
+     *
+     * @return <code>true</code> if <code>XPathFactory</code> supports <code>objectModel</code>, else <code>false</code>.
+     *
+     * @throws NullPointerException If <code>objectModel</code> is <code>null</code>.
+     * @throws IllegalArgumentException If <code>objectModel.length() == 0</code>.
+     */
+    public abstract boolean isObjectModelSupported(String objectModel);
 
     /**
      * <p>Set a feature for this <code>XPathFactory</code> and
@@ -314,8 +314,8 @@
      *   it creates cannot support this feature.
      * @throws NullPointerException if <code>name</code> is <code>null</code>.
      */
-        public abstract void setFeature(String name, boolean value)
-                throws XPathFactoryConfigurationException;
+    public abstract void setFeature(String name, boolean value)
+            throws XPathFactoryConfigurationException;
 
     /**
      * <p>Get the state of the named feature.</p>
@@ -339,8 +339,8 @@
      *   it creates cannot support this feature.
      * @throws NullPointerException if <code>name</code> is <code>null</code>.
      */
-        public abstract boolean getFeature(String name)
-                throws XPathFactoryConfigurationException;
+    public abstract boolean getFeature(String name)
+            throws XPathFactoryConfigurationException;
 
     /**
      * <p>Establish a default variable resolver.</p>
@@ -359,19 +359,19 @@
     public abstract void setXPathVariableResolver(XPathVariableResolver resolver);
 
     /**
-       * <p>Establish a default function resolver.</p>
-       *
-       * <p>Any <code>XPath</code> objects constructed from this factory will
-       * use the specified resolver by default.</p>
-       *
-       * <p>A <code>NullPointerException</code> is thrown if
-       * <code>resolver</code> is <code>null</code>.</p>
-       *
-       * @param resolver XPath function resolver.
-       *
-       * @throws NullPointerException If <code>resolver</code> is
-       *   <code>null</code>.
-       */
+     * <p>Establish a default function resolver.</p>
+     *
+     * <p>Any <code>XPath</code> objects constructed from this factory will
+     * use the specified resolver by default.</p>
+     *
+     * <p>A <code>NullPointerException</code> is thrown if
+     * <code>resolver</code> is <code>null</code>.</p>
+     *
+     * @param resolver XPath function resolver.
+     *
+     * @throws NullPointerException If <code>resolver</code> is
+     *   <code>null</code>.
+     */
     public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver);
 
     /**
--- a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java	Wed May 08 11:22:25 2013 +0100
+++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,20 +25,16 @@
 
 package javax.xml.xpath;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
 import java.net.URL;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Properties;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 
 /**
  * Implementation of {@link XPathFactory#newInstance(String)}.
@@ -50,7 +46,7 @@
 class XPathFactoryFinder  {
     private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal";
 
-    private static SecuritySupport ss = new SecuritySupport() ;
+    private static final SecuritySupport ss = new SecuritySupport() ;
     /** debug support code. */
     private static boolean debug = false;
     static {
@@ -65,12 +61,12 @@
     /**
      * <p>Cache properties for performance.</p>
      */
-        private static Properties cacheProps = new Properties();
+    private static final Properties cacheProps = new Properties();
 
-        /**
-         * <p>First time requires initialization overhead.</p>
-         */
-        private volatile static boolean firstTime = true;
+    /**
+     * <p>First time requires initialization overhead.</p>
+     */
+    private volatile static boolean firstTime = true;
 
     /**
      * <p>Conditional debug printing.</p>
@@ -93,9 +89,8 @@
      * to find <code>XPathFactory</code>.</p>
      *
      * @param loader
-     *      to be used to load resource, {@link XPathFactory}, and
-     *      {@link SchemaFactoryLoader} implementations during
-     *      the resolution process.
+     *      to be used to load resource and {@link XPathFactory}
+     *      implementations during the resolution process.
      *      If this parameter is null, the default system class loader
      *      will be used.
      */
@@ -113,7 +108,7 @@
                 return;
             }
         } catch( Throwable unused ) {
-            ; // getContextClassLoader() undefined in JDK1.1
+             // getContextClassLoader() undefined in JDK1.1
         }
 
         if( classLoader==ClassLoader.getSystemClassLoader() ) {
@@ -126,7 +121,7 @@
 
     /**
      * <p>Creates a new {@link XPathFactory} object for the specified
-     * schema language.</p>
+     * object model.</p>
      *
      * @param uri
      *       Identifies the underlying object model.
@@ -136,8 +131,10 @@
      * @throws NullPointerException
      *      If the parameter is null.
      */
-    public XPathFactory newFactory(String uri) {
-        if(uri==null)        throw new NullPointerException();
+    public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException {
+        if (uri == null) {
+            throw new NullPointerException();
+        }
         XPathFactory f = _newFactory(uri);
         if (f != null) {
             debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri);
@@ -154,8 +151,8 @@
      *
      * @return {@link XPathFactory} for the given object model.
      */
-    private XPathFactory _newFactory(String uri) {
-        XPathFactory xpathFactory;
+    private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException {
+        XPathFactory xpathFactory = null;
 
         String propertyName = SERVICE_CLASS.getName() + ":" + uri;
 
@@ -166,7 +163,9 @@
             if(r!=null) {
                 debugPrintln("The value is '"+r+"'");
                 xpathFactory = createInstance(r, true);
-                if(xpathFactory != null)    return xpathFactory;
+                if (xpathFactory != null) {
+                    return xpathFactory;
+                }
             } else
                 debugPrintln("The property is undefined.");
         } catch( Throwable t ) {
@@ -180,8 +179,6 @@
         String configFile = javah + File.separator +
         "lib" + File.separator + "jaxp.properties";
 
-        String factoryClassName = null ;
-
         // try to read from $java.home/lib/jaxp.properties
         try {
             if(firstTime){
@@ -196,7 +193,7 @@
                     }
                 }
             }
-            factoryClassName = cacheProps.getProperty(propertyName);
+            final String factoryClassName = cacheProps.getProperty(propertyName);
             debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties");
 
             if (factoryClassName != null) {
@@ -211,23 +208,16 @@
             }
         }
 
-        // try META-INF/services files
-        Iterator sitr = createServiceFileIterator();
-        while(sitr.hasNext()) {
-            URL resource = (URL)sitr.next();
-            debugPrintln("looking into " + resource);
-            try {
-                xpathFactory = loadFromService(uri, resource.toExternalForm(),
-                                                ss.getURLInputStream(resource));
-                if (xpathFactory != null) {
-                    return xpathFactory;
-                }
-            } catch(IOException e) {
-                if( debug ) {
-                    debugPrintln("failed to read "+resource);
-                    e.printStackTrace();
-                }
-            }
+        // Try with ServiceLoader
+        assert xpathFactory == null;
+        xpathFactory = findServiceProvider(uri);
+
+        // The following assertion should always be true.
+        // Uncomment it, recompile, and run with -ea in case of doubts:
+        // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri);
+
+        if (xpathFactory != null) {
+            return xpathFactory;
         }
 
         // platform default
@@ -245,8 +235,8 @@
      * @param className Name of class to create.
      * @return Created class or <code>null</code>.
      */
-    private Class createClass(String className) {
-            Class clazz;
+    private Class<?> createClass(String className) {
+        Class clazz;
         // make sure we have access to restricted packages
         boolean internal = false;
         if (System.getSecurityManager() != null) {
@@ -258,47 +248,54 @@
         // use approprite ClassLoader
         try {
             if (classLoader != null && !internal) {
-                    clazz = classLoader.loadClass(className);
+                    clazz = Class.forName(className, false, classLoader);
             } else {
                     clazz = Class.forName(className);
             }
         } catch (Throwable t) {
-            if(debug)   t.printStackTrace();
-                return null;
+            if(debug) {
+                t.printStackTrace();
+            }
+            return null;
         }
 
-            return clazz;
+        return clazz;
     }
 
     /**
      * <p>Creates an instance of the specified and returns it.</p>
      *
      * @param className
-     *      fully qualified class name to be instanciated.
+     *      fully qualified class name to be instantiated.
      *
      * @return null
      *      if it fails. Error messages will be printed by this method.
      */
-    XPathFactory createInstance( String className ) {
+    XPathFactory createInstance( String className )
+            throws XPathFactoryConfigurationException
+    {
         return createInstance( className, false );
     }
-    XPathFactory createInstance( String className, boolean useServicesMechanism  ) {
+
+    XPathFactory createInstance( String className, boolean useServicesMechanism  )
+            throws XPathFactoryConfigurationException
+    {
         XPathFactory xPathFactory = null;
 
         debugPrintln("createInstance(" + className + ")");
 
         // get Class from className
-        Class clazz = createClass(className);
+        Class<?> clazz = createClass(className);
         if (clazz == null) {
-                debugPrintln("failed to getClass(" + className + ")");
-                return null;
+            debugPrintln("failed to getClass(" + className + ")");
+            return null;
         }
         debugPrintln("loaded " + className + " from " + which(clazz));
 
         // instantiate Class as a XPathFactory
         try {
             if (!useServicesMechanism) {
-                xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz);
+                xPathFactory = newInstanceNoServiceLoader(clazz);
             }
             if (xPathFactory == null) {
                 xPathFactory = (XPathFactory) clazz.newInstance();
@@ -329,203 +326,94 @@
      * Try to construct using newXPathFactoryNoServiceLoader
      *   method if available.
      */
-    private static Object newInstanceNoServiceLoader(
+    private static XPathFactory newInstanceNoServiceLoader(
          Class<?> providerClass
-    ) {
+    ) throws XPathFactoryConfigurationException {
         // Retain maximum compatibility if no security manager.
         if (System.getSecurityManager() == null) {
             return null;
         }
         try {
             Method creationMethod =
-                providerClass.getDeclaredMethod(
-                    "newXPathFactoryNoServiceLoader"
-                );
-                return creationMethod.invoke(null, (Object[])null);
-            } catch (NoSuchMethodException exc) {
-                return null;
-            } catch (Exception exc) {
-                return null;
-        }
-    }
-
-    /**
-     * <p>Look up a value in a property file.</p>
-     *
-     * <p>Set <code>debug</code> to <code>true</code> to trace property evaluation.</p>
-     *
-     * @param objectModel URI of object model to support.
-     * @param inputName Name of <code>InputStream</code>.
-     * @param in <code>InputStream</code> of properties.
-     *
-     * @return <code>XPathFactory</code> as determined by <code>keyName</code> value or <code>null</code> if there was an error.
-     *
-     * @throws IOException If IO error reading from <code>in</code>.
-     */
-    private XPathFactory loadFromService(
-            String objectModel,
-            String inputName,
-            InputStream in)
-            throws IOException {
-
-            XPathFactory xPathFactory = null;
-            final Class[] stringClassArray = {"".getClass()};
-            final Object[] objectModelObjectArray = {objectModel};
-            final String isObjectModelSupportedMethod = "isObjectModelSupported";
-
-            debugPrintln("Reading " + inputName);
+                    providerClass.getDeclaredMethod(
+                        "newXPathFactoryNoServiceLoader"
+                    );
+            final int modifiers = creationMethod.getModifiers();
 
-            // read from InputStream until a match is found
-            BufferedReader configFile = new BufferedReader(new InputStreamReader(in));
-            String line = null;
-            while ((line = configFile.readLine()) != null) {
-                    // '#' is comment char
-                    int comment = line.indexOf("#");
-                    switch (comment) {
-                            case -1: break; // no comment
-                            case 0: line = ""; break; // entire line is a comment
-                            default: line = line.substring(0, comment); break; // trim comment
-                    }
-
-                    // trim whitespace
-                    line = line.trim();
-
-                    // any content left on line?
-                    if (line.length() == 0) {
-                            continue;
-                    }
-
-                    // line content is now the name of the class
-                    Class clazz = createClass(line);
-                    if (clazz == null) {
-                            continue;
-                    }
-
-                    // create an instance of the Class
-                    try {
-                            xPathFactory = (XPathFactory) clazz.newInstance();
-                    } catch (ClassCastException classCastExcpetion) {
-                            xPathFactory = null;
-                            continue;
-                    } catch (InstantiationException instantiationException) {
-                            xPathFactory = null;
-                            continue;
-                    } catch (IllegalAccessException illegalAccessException) {
-                            xPathFactory = null;
-                            continue;
-                    }
-
-                    // does this Class support desired object model?
-                    try {
-                            Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray);
-                            Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray);
-                            if (supported.booleanValue()) {
-                                    break;
-                            }
-
-                    } catch (NoSuchMethodException noSuchMethodException) {
-
-                    } catch (IllegalAccessException illegalAccessException) {
-
-                    } catch (InvocationTargetException invocationTargetException) {
-
-                    }
-                    xPathFactory = null;
+            // Do not call "newXPathFactoryNoServiceLoader" if it's
+            // not public static.
+            if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
+                return null;
             }
 
-            // clean up
-            configFile.close();
-
-            // return new instance of XPathFactory or null
-            return xPathFactory;
-    }
-
-    /** Iterator that lazily computes one value and returns it. */
-    private static abstract class SingleIterator implements Iterator {
-        private boolean seen = false;
-
-        public final void remove() { throw new UnsupportedOperationException(); }
-        public final boolean hasNext() { return !seen; }
-        public final Object next() {
-            if(seen)    throw new NoSuchElementException();
-            seen = true;
-            return value();
-        }
-
-        protected abstract Object value();
-    }
-
-    /**
-     * Looks up a value in a property file
-     * while producing all sorts of debug messages.
-     *
-     * @return null
-     *      if there was an error.
-     */
-    private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in )
-        throws IOException {
-        debugPrintln("Reading "+resourceName );
-
-        Properties props = new Properties();
-        props.load(in);
-        in.close();
-        String factoryClassName = props.getProperty(keyName);
-        if(factoryClassName != null){
-            debugPrintln("found "+keyName+" = " + factoryClassName);
-            return createInstance(factoryClassName, true);
-        } else {
-            debugPrintln(keyName+" is not in the property file");
+            // Only calls "newXPathFactoryNoServiceLoader" if it's
+            // declared to return an instance of XPathFactory.
+            final Class<?> returnType = creationMethod.getReturnType();
+            if (SERVICE_CLASS.isAssignableFrom(returnType)) {
+                return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null));
+            } else {
+                // Should not happen since
+                // XPathFactoryImpl.newXPathFactoryNoServiceLoader is
+                // declared to return XPathFactory.
+                throw new ClassCastException(returnType
+                            + " cannot be cast to " + SERVICE_CLASS);
+            }
+        } catch (ClassCastException e) {
+            throw new XPathFactoryConfigurationException(e);
+        } catch (NoSuchMethodException exc) {
+            return null;
+        } catch (Exception exc) {
             return null;
         }
     }
 
+    // Call isObjectModelSupportedBy with initial context.
+    private boolean isObjectModelSupportedBy(final XPathFactory factory,
+            final String objectModel,
+            AccessControlContext acc) {
+        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        return factory.isObjectModelSupported(objectModel);
+                    }
+                }, acc);
+    }
+
     /**
-     * Returns an {@link Iterator} that enumerates all
-     * the META-INF/services files that we care.
+     * Finds a service provider subclass of XPathFactory that supports the
+     * given object model using the ServiceLoader.
+     *
+     * @param objectModel URI of object model to support.
+     * @return An XPathFactory supporting the specified object model, or null
+     *         if none is found.
+     * @throws XPathFactoryConfigurationException if a configuration error is found.
      */
-    private Iterator createServiceFileIterator() {
-        if (classLoader == null) {
-            return new SingleIterator() {
-                protected Object value() {
-                    ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader();
-                    return ss.getResourceAsURL(classLoader, SERVICE_ID);
-                    //return (ClassLoader.getSystemResource( SERVICE_ID ));
-                }
-            };
-        } else {
-            try {
-                //final Enumeration e = classLoader.getResources(SERVICE_ID);
-                final Enumeration e = ss.getResources(classLoader, SERVICE_ID);
-                if(!e.hasMoreElements()) {
-                    debugPrintln("no "+SERVICE_ID+" file was found");
+    private XPathFactory findServiceProvider(final String objectModel)
+            throws XPathFactoryConfigurationException {
+
+        assert objectModel != null;
+        // store current context.
+        final AccessControlContext acc = AccessController.getContext();
+        try {
+            return AccessController.doPrivileged(new PrivilegedAction<XPathFactory>() {
+                public XPathFactory run() {
+                    final ServiceLoader<XPathFactory> loader =
+                            ServiceLoader.load(SERVICE_CLASS);
+                    for (XPathFactory factory : loader) {
+                        // restore initial context to call
+                        // factory.isObjectModelSupportedBy
+                        if (isObjectModelSupportedBy(factory, objectModel, acc)) {
+                            return factory;
+                        }
+                    }
+                    return null; // no factory found.
                 }
-
-                // wrap it into an Iterator.
-                return new Iterator() {
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public boolean hasNext() {
-                        return e.hasMoreElements();
-                    }
-
-                    public Object next() {
-                        return e.nextElement();
-                    }
-                };
-            } catch (IOException e) {
-                debugPrintln("failed to enumerate resources "+SERVICE_ID);
-                if(debug)   e.printStackTrace();
-                return new ArrayList().iterator();  // empty iterator
-            }
+            });
+        } catch (ServiceConfigurationError error) {
+            throw new XPathFactoryConfigurationException(error);
         }
     }
 
-    private static final Class SERVICE_CLASS = XPathFactory.class;
-    private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName();
-
-
+    private static final Class<XPathFactory> SERVICE_CLASS = XPathFactory.class;
 
     private static String which( Class clazz ) {
         return which( clazz.getName(), clazz.getClassLoader() );
--- a/jaxws/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/jaxws/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 8c0b6bccfe474576d6b30d1582c4329029330150 jdk8-b85
 a5e7c2f093c9996ab3419db1565094a07b059e9c jdk8-b86
 72e03566f0a61282cc48ebc869803b256cccd66c jdk8-b87
+24fa5452e5d4e9df8b85196283275a6ca4b4adb4 jdk8-b88
+88838e08e4ef6a254867c8126070a1975683108d jdk8-b89
--- a/jdk/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -210,3 +210,4 @@
 7989cd0cc3a9149864589438ee2c949015d8aa9a jdk8-b86
 d5228e624826a10ccc5b05f30ad8d839b58fe48d jdk8-b87
 8dbb4b159e04de3c447c9242c70505e71f8624c7 jdk8-b88
+845025546e35519fbb8970e79fc2a834063a5e19 jdk8-b89
--- a/jdk/makefiles/CompileNativeLibraries.gmk	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/makefiles/CompileNativeLibraries.gmk	Thu May 16 11:47:51 2013 +0100
@@ -63,7 +63,12 @@
 # Use this variable to set DEBUG_SYMBOLS true on windows for all libraries, but
 # not on other platforms.
 ifeq ($(OPENJDK_TARGET_OS), windows)
-    WINDOWS_ONLY := true
+    DEBUG_ALL_BINARIES := true
+endif
+
+# Build everything with debugging on OpenJDK
+ifdef OPENJDK
+    DEBUG_ALL_BINARIES := true
 endif
 
 #
@@ -91,7 +96,8 @@
 			-I$(JDK_TOPDIR)/src/share/native/java/lang/fdlibm/include,\
 		CFLAGS_windows_debug:=-DLOGGING,\
 		ARFLAGS:=$(ARFLAGS),\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libfdlibm))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libfdlibm,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 else
 
@@ -105,7 +111,8 @@
 		CFLAGS:=$(CFLAGS_JDKLIB) \
 			-I$(JDK_TOPDIR)/src/share/native/java/lang/fdlibm/include,\
 		LDFLAGS:=-nostdlib -r -arch x86_64,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libfdlibm))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libfdlibm,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBFDLIBM := $(JDK_OUTPUTDIR)/objs/$(LIBRARY_PREFIX)fdlibm$(STATIC_LIBRARY_SUFFIX)
 $(BUILD_LIBFDLIBM) : $(BUILD_LIBFDLIBM_MAC)
@@ -257,7 +264,7 @@
 			  -D "JDK_FTYPE=0x2L",\
 		REORDER:=$(LIBJAVA_REORDER), \
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjava,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJAVA)
 
@@ -308,7 +315,7 @@
 			  -D "JDK_INTERNAL_NAME=mlib_image" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libmlib_image,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBMLIB_IMAGE) : $(BUILD_LIBJAVA)
 
@@ -431,7 +438,8 @@
                          $(BUILD_LIBMLIB_LDLIBS) -ljava -ljvm \
 			 $(call SET_SHARED_LIBRARY_ORIGIN),\
 		LDFLAGS_SUFFIX_solaris:=-lc,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libmlib_image_v))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libmlib_image_v,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBMLIB_IMAGE_V): $(BUILD_LIBJAVA)
 
@@ -739,7 +747,7 @@
 			  -D "JDK_INTERNAL_NAME=awt" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBAWT) : $(BUILD_LIBJAVA)
 
@@ -895,7 +903,8 @@
 			  -D "JDK_FNAME=xawt.dll" \
 			  -D "JDK_INTERNAL_NAME=xawt" \
 			  -D "JDK_FTYPE=0x2L",\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_xawt))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_xawt,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBAWT_XAWT) : $(BUILD_LIBJAVA)
 
@@ -956,7 +965,7 @@
 			  -D "JDK_INTERNAL_NAME=zip" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libzip,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBZIP) : $(BUILD_LIBJAVA)
 
@@ -986,7 +995,7 @@
 			  -D "JDK_FNAME=unpack.dll" \
 			  -D "JDK_INTERNAL_NAME=unpack" \
 			  -D "JDK_FTYPE=0x2L",\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBUNPACK) : $(BUILD_LIBJAVA)
 
@@ -1100,7 +1109,7 @@
 			  -D "JDK_INTERNAL_NAME=dt_shmem" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libdt_shmem,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
   BUILD_LIBRARIES += $(BUILD_LIBDT_SHMEM)
 
@@ -1134,7 +1143,7 @@
 			  -D "JDK_INTERNAL_NAME=jdwp" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjdwp,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJDWP) : $(BUILD_LIBJAVA)
 
@@ -1175,7 +1184,7 @@
 			  -D "JDK_INTERNAL_NAME=$(LIBJAAS_NAME)" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjaas,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJAAS) : $(BUILD_LIBJAVA)
 
@@ -1240,7 +1249,7 @@
 			  -D "JDK_INTERNAL_NAME=lcms" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/liblcms,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
     BUILD_LIBRARIES += $(BUILD_LIBLCMS)
 
@@ -1300,7 +1309,7 @@
 			  -D "JDK_FTYPE=0x2L",\
 		REORDER:=$(BUILD_LIBJPEG_REORDER),\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjpeg,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJPEG) : $(BUILD_LIBJAVA)
 
@@ -1377,7 +1386,7 @@
 			  -D "JDK_INTERNAL_NAME=fontmanager" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libfontmanager,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBFONTMANAGER) : $(BUILD_LIBAWT)
 
@@ -1434,7 +1443,7 @@
 			  -D "JDK_INTERNAL_NAME=t2k" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libt2k,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
     # t2k is linked against fontmanager
     $(BUILD_LIBT2K) : $(BUILD_LIBFONTMANAGER)
@@ -1472,7 +1481,7 @@
 			  -D "JDK_INTERNAL_NAME=jawt" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjawt,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJAWT) : $(BUILD_LIBAWT)
 
@@ -1521,7 +1530,8 @@
 		LDFLAGS_SUFFIX_solaris:=$(JAWT_LIBS) $(LDFLAGS_JDKLIB_SUFFIX) -lXrender,\
 		LDFLAGS_SUFFIX_macosx:=-Xlinker -rpath -Xlinker @loader_path $(JAWT_LIBS) \
 				       -framework Cocoa $(LDFLAGS_JDKLIB_SUFFIX),\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjawt))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjawt,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 ifndef BUILD_HEADLESS_ONLY
 $(BUILD_LIBJAWT) : $(BUILD_LIBAWT_XAWT)
@@ -1828,7 +1838,7 @@
 			  -D "JDK_INTERNAL_NAME=net" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libnet,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBNET) : $(BUILD_LIBJAVA)
 
@@ -1965,7 +1975,7 @@
 			  -D "JDK_INTERNAL_NAME=nio" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libnio,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBNIO)
 
@@ -2002,7 +2012,8 @@
 		LDFLAGS_SUFFIX_posix:=-lnio -lnet,\
 		LDFLAGS_SUFFIX_solaris:=-lsocket -ljava -ljvm -lc,\
 		LDFLAGS_SUFFIX_macosx:=-ljava -ljvm,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsctp))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsctp,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
     BUILD_LIBRARIES += $(BUILD_LIBSCTP)
 
@@ -2126,7 +2137,7 @@
 			  -D "JDK_INTERNAL_NAME=jli" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjli,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJLI)
 
@@ -2143,7 +2154,8 @@
 		OPTIMIZATION:=HIGH, \
 		CFLAGS:=$(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS),\
 		ARFLAGS:=$(ARFLAGS),\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjli_static))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjli_static,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJLI_STATIC)
 
@@ -2161,7 +2173,8 @@
 		OPTIMIZATION:=HIGH, \
 		CFLAGS:=$(CFLAGS_JDKLIB) $(LIBJLI_CFLAGS),\
 		LDFLAGS:=-nostdlib -r,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjli_static))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjli_static,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(JDK_OUTPUTDIR)/objs/libjli_static.a : $(BUILD_LIBJLI_STATIC)
 	$(call install-file)
@@ -2192,7 +2205,7 @@
 			  -D "JDK_INTERNAL_NAME=jfr" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjfr,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJFR)
 
@@ -2244,7 +2257,7 @@
 			  -D "JDK_INTERNAL_NAME=kcms" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libkcms,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBKCMS) : $(BUILD_LIBJAVA)
 
@@ -2279,7 +2292,8 @@
 		LDFLAGS:=$(LDFLAGS_JDKLIB) \
 			 $(call SET_SHARED_LIBRARY_ORIGIN), \
 		LDFLAGS_SUFFIX:=-L$(OPENWIN_LIB)$(OPENJDK_TARGET_CPU_ISADIR) -R$(OPENWIN_LIB)$(OPENJDK_TARGET_CPU_ISADIR) -ldga -lX11 $(LIBDL) -lc, \
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsunwjdga))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsunwjdga,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBSUNWJDGA)
 
@@ -2369,7 +2383,8 @@
 		LDFLAGS_SUFFIX_linux:=-ljvm -lawt -lm $(LIBDL) -ljava,\
 		LDFLAGS_SUFFIX_solaris:=$(LIBDL) -ljvm -lawt -lm -ljava $(LIBCXX) -lc,\
 		LDFLAGS_SUFFIX_macosx:=-ljvm $(LIBCXX) -lawt $(LIBDL) -ljava,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_headless))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_headless,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBAWT_HEADLESS) : $(BUILD_LIBAWT)
 
@@ -2462,7 +2477,7 @@
 			  -D "JDK_INTERNAL_NAME=splashscreen" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsplashscreen,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(LIBSPLASHSCREEN)
 
@@ -2504,7 +2519,7 @@
 			  -D "JDK_INTERNAL_NAME=dcpr" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libdcpr,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBDCPR) : $(BUILD_LIBJAVA)
 
@@ -2538,7 +2553,7 @@
 			  -D "JDK_INTERNAL_NAME=j2pcsc" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2pcsc,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJ2PCSC)
 
@@ -2561,7 +2576,8 @@
 			 $(call SET_SHARED_LIBRARY_ORIGIN),\
 		LDFLAGS_SUFFIX:=$(LIBDL),\
 		LDFLAGS_SUFFIX_solaris:=-lc,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2gss))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2gss,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJ2GSS)
 endif
@@ -2601,7 +2617,7 @@
 			  -D "JDK_INTERNAL_NAME=$(BUILD_LIBKRB5_NAME)" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libkrb5,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBKRB5)
 endif
@@ -2627,7 +2643,7 @@
 			  -D "JDK_INTERNAL_NAME=sunmscapi" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsunmscapi,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBSUNMSCAPI)
 endif
@@ -2659,7 +2675,7 @@
 			  -D "JDK_INTERNAL_NAME=j2pkcs11" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2pkcs11,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBJ2PKCS11)
 
@@ -2705,7 +2721,7 @@
 			  -D "JDK_INTERNAL_NAME=sunec" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libsunec,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBSUNEC)
 endif
@@ -2849,7 +2865,7 @@
 			  -D "JDK_INTERNAL_NAME=jsound" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjsound,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJSOUND) : $(BUILD_LIBJAVA)
 
@@ -2884,7 +2900,8 @@
 		LDFLAGS:=$(LDFLAGS_JDKLIB)\
 			 $(call SET_SHARED_LIBRARY_ORIGIN),\
 		LDFLAGS_SUFFIX:=-lasound -ljava -ljvm,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjsoundalsa))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjsoundalsa,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJSOUNDALSA) : $(BUILD_LIBJAVA)
 
@@ -2917,7 +2934,7 @@
 			  -D "JDK_INTERNAL_NAME=jsoundds" \
 			  -D "JDK_FTYPE=0x2L",\
 		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjsoundds,\
-		DEBUG_SYMBOLS:=$(WINDOWS_ONLY)))
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJSOUNDDS) : $(BUILD_LIBJAVA)
 
@@ -2942,7 +2959,8 @@
 		LDFLAGS:=$(LDFLAGS_JDKLIB),\
 		LDFLAGS_SUFFIX:=$(LIBDL),\
 		LDFLAGS_SUFFIX_solaris:=-lc,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2ucrypto))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libj2ucrypto,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBJ2UCRYPTO) : $(BUILD_LIBJAVA)
 
@@ -2972,7 +2990,8 @@
                                 -F/System/Library/Frameworks/JavaVM.framework/Frameworks \
                                 -framework JavaNativeFoundation \
                                 $(LDFLAGS_JDKLIB_SUFFIX),\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libAppleScriptEngine))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libAppleScriptEngine,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(BUILD_LIBAPPLESCRIPTENGINE) : $(BUILD_LIBJAVA)
 
@@ -3011,7 +3030,8 @@
 	-framework OpenGL \
 	-framework IOSurface \
 	-framework QuartzCore, \
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosxapp))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosxapp,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBOSXAPP)
 
@@ -3051,7 +3071,8 @@
     -framework Security \
     -framework SystemConfiguration \
     $(LDFLAGS_JDKLIB_SUFFIX), \
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosx))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosx,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBOSX)
 
@@ -3184,7 +3205,8 @@
 				       -framework JavaRuntimeSupport \
 				       -framework OpenGL \
 				       -framework QuartzCore -ljava,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_lwawt))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libawt_lwawt,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBAWT_LWAWT)
 
@@ -3224,7 +3246,8 @@
 				       -framework JavaNativeFoundation \
 				       -framework JavaRuntimeSupport \
 				       -ljava -ljvm,\
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosxui))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libosxui,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 BUILD_LIBRARIES += $(BUILD_LIBOSXUI)
 
@@ -3264,7 +3287,8 @@
                                   -F/System/Library/Frameworks/JavaVM.framework/Frameworks \
                                   -framework JavaNativeFoundation \
                                   -lffi, \
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjobjc32))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjobjc32,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(eval $(call SetupNativeCompilation,BUILD_LIBJOBJC64,\
 		LIBRARY:=JObjC,\
@@ -3288,7 +3312,8 @@
                                   -F/System/Library/Frameworks/JavaVM.framework/Frameworks \
                                   -framework JavaNativeFoundation \
                                   -lffi, \
-		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjobjc64))
+		OBJECT_DIR:=$(JDK_OUTPUTDIR)/objs/libjobjc64,\
+		DEBUG_SYMBOLS:=$(DEBUG_ALL_BINARIES)))
 
 $(INSTALL_LIBRARIES_HERE)/$(LIBRARY_PREFIX)JObjC$(SHARED_LIBRARY_SUFFIX): $(BUILD_LIBJOBJC32) $(BUILD_LIBJOBJC64)
 	$(LIPO) -create -output $@ $(BUILD_LIBJOBJC32) $(BUILD_LIBJOBJC64)
--- a/jdk/src/share/classes/java/util/Base64.java	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/Base64.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
--- a/jdk/src/share/classes/java/util/StringJoiner.java	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/src/share/classes/java/util/StringJoiner.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * 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
--- a/jdk/test/java/lang/CharSequence/DefaultTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/test/java/lang/CharSequence/DefaultTest.java	Thu May 16 11:47:51 2013 +0100
@@ -1,12 +1,10 @@
 /*
- * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * 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.
+ * 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
--- a/jdk/test/java/util/StringJoiner/StringJoinerTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/jdk/test/java/util/StringJoiner/StringJoinerTest.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * 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
--- a/langtools/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -209,3 +209,5 @@
 4a48f31735349782ad13980267358c97076adc66 jdk8-b85
 6ab578e141dfd17c4dc03869bb204aafa490c9f4 jdk8-b86
 1329f9c38d93c8caf339d7687df8371d06fe9e56 jdk8-b87
+a1e10f3adc47c8602a72e43a41403a642e73e0b1 jdk8-b88
+ec434cfd2752a7742c875c2fe7d556d8b81c0f3a jdk8-b89
--- a/langtools/make/Makefile-classic	Wed May 08 11:22:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,396 +0,0 @@
-#
-# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  Oracle designates this
-# particular file as subject to the "Classpath" exception as provided
-# by Oracle in the LICENSE file that accompanied this code.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-#
-# Makefile for building the langtools workspace.
-#
-
-#
-# On Solaris, the standard 'make' utility will not work with these makefiles.
-#    This little rule is only understood by Solaris make, and is harmless
-#    when seen by the GNU make tool. If using Solaris make, this causes the
-#    make command to fail.
-#
-SUN_MAKE_TEST:sh = @echo "ERROR: PLEASE USE GNU VERSION OF MAKE"; exit 33
-
-#----- cancel implicit rules
-
-%: %.o
-%: %.obj
-%: %.dll
-%: %.c
-%: %.cc
-%: %.C
-%: %.p
-%: %.f
-%: %.s
-%: %.F
-%: %.r
-%: %.S
-%: %.mod
-%: %.sh
-%: %,v
-%: RCS/%,v
-
-#----- imports
-
-ifdef ALT_BOOT_JAVA_HOME
-  BOOT_JAVA_HOME = $(ALT_BOOT_JAVA_HOME)
-else 
-  ifdef ALT_BOOTDIR
-    BOOT_JAVA_HOME = $(ALT_BOOTDIR)
-  else
-    BOOT_JAVA_HOME=/java/re/jdk/1.5.0/archive/fcs/binaries/solaris-sparc
-  endif
-endif
-
-BOOT_JAVA=$(BOOT_JAVA_HOME)/bin/java
-BOOT_JAVAC=$(BOOT_JAVA_HOME)/bin/javac
-BOOTJAR=$(BOOT_JAVA_HOME)/bin/jar
-
-ifdef ALT_TESTJAVA_HOME
-  TESTJAVA_HOME = $(ALT_TESTJAVA_HOME)
-else
-  TESTJAVA_HOME=/java/re/jdk/1.6.0/archive/fcs/binaries/solaris-sparc
-endif
-
-TESTJAVA=$(TESTJAVA_HOME)/bin/java
-
-ifdef ALT_FINDBUGS_HOME
-  FINDBUGS_HOME = $(ALT_FINDBUGS_HOME)
-else
-  FINDBUGS_HOME = /java/devtools/share/findbugs/1.1.2-rc4
-endif
-
-FINDBUGS = $(FINDBUGS_HOME)/bin/findbugs
-
-#----- commands
-
-CHMOD = chmod
-CP = cp
-ECHO = echo # FIXME
-FIND = find
-MKDIR = mkdir
-SED = sed
-ZIP = zip
-
-#-----  locations and deliverables
-
-TOPDIR = ..
-SRC_BIN_DIR = $(TOPDIR)/src/share/bin
-SRC_CLASSES_DIR = $(TOPDIR)/src/share/classes
-
-BUILD_DIR = $(TOPDIR)/build
-
-CLASSES_DIR = $(BUILD_DIR)/classes
-GENSRC_DIR = $(BUILD_DIR)/gensrc
-
-DIST_DIR = $(TOPDIR)/dist
-BIN_DIR = $(DIST_DIR)/bin
-LIB_DIR = $(DIST_DIR)/lib
-
-JAVAC_JAR = $(LIB_DIR)/javac.jar
-JAVADOC_JAR = $(LIB_DIR)/javadoc.jar
-JAVAH_JAR = $(LIB_DIR)/javah.jar
-JAVAP_JAR = $(LIB_DIR)/javap.jar
-
-CLASSES_JAR = $(DIST_DIR)/classes.jar
-SRC_ZIP = $(DIST_DIR)/src.zip
-
-BUILDTOOLSRC_DIR = tools
-BUILDTOOLCLASSES_DIR = $(BUILD_DIR)/toolclasses
-
-#-----
-
-ifndef JDK_MAJOR_VERSION
-  JDK_MAJOR_VERSION = 1
-endif
-
-ifndef JDK_MINOR_VERSION
-  JDK_MINOR_VERSION = 7
-endif
-
-ifndef JDK_MICRO_VERSION
-  JDK_MICRO_VERSION = 0
-endif
-
-ifndef JDK_VERSION
-  JDK_VERSION = $(JDK_MAJOR_VERSION).$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION)
-endif
-
-ifndef MILESTONE
-  MILESTONE = internal
-endif
-
-# RELEASE is JDK_VERSION and -MILESTONE if MILESTONE is set
-ifneq ($(MILESTONE),fcs)
-  RELEASE      = $(JDK_VERSION)-$(MILESTONE)$(BUILD_VARIANT_RELEASE)
-else
-  RELEASE      = $(JDK_VERSION)$(BUILD_VARIANT_RELEASE)
-endif
-
-# FULL_VERSION is RELEASE and -BUILD_NUMBER if BUILD_NUMBER is set
-ifdef BUILD_NUMBER
-  FULL_VERSION = $(RELEASE)-$(BUILD_NUMBER)
-else
-  BUILD_NUMBER = b00
-  USER_RELEASE_SUFFIX := $(shell echo $(USER)_`date '+%d_%b_%Y_%H_%M' | tr "A-Z" "a-z"`)
-  FULL_VERSION = $(RELEASE)-$(USER_RELEASE_SUFFIX)-$(BUILD_NUMBER)
-endif
-
-#----- useful macros
-
-TOOLS =  javac javadoc javah javap
-
-SOURCE_LEVEL = 5
-BOOTSTRAP_TARGET_LEVEL = 5
-TARGET_LEVEL = 6
-
-ifndef TARGET_JAVA
-  TARGET_JAVA = java
-endif
-
-NO_PROPRIETARY_API_WARNINGS = -XDignore.symbol.file=true
-
-SELF = $(lastword $(MAKEFILE_LIST))
-
-#-----
-
-# the default is to generate the following:
-# dist/{bin,lib}: 
-# 	lang tools compiled to run on the target JDK
-
-default:  
-	$(MAKE) -f $(SELF) \
-		MILESTONE=bootstrap \
-		TARGET_LEVEL=$(BOOTSTRAP_TARGET_LEVEL) \
-		TARGET_JAVA=$(BOOT_JAVA_HOME)/bin/java \
-		GENSRC_DIR=$(BUILD_DIR)/bootstrap/gensrc \
-		CLASSES_DIR=$(BUILD_DIR)/bootstrap/classes \
-		BIN_DIR=$(BUILD_DIR)/bootstrap/bin \
-		LIB_DIR=$(BUILD_DIR)/bootstrap/lib \
-		$(BUILD_DIR)/bootstrap/lib/javac.jar \
-		$(BUILD_DIR)/bootstrap/bin/javac
-	$(MAKE) -f $(SELF) \
-		BOOT_JAVAC=$(BUILD_DIR)/bootstrap/bin/javac \
-		tools
-
-# for jdk, we generate the following:
-# dist/bootstrap/{bin,lib}:
-#	lang tools compiled to run on the boot JDK
-# dist/lib/classes.jar:
-#	lang tools recompiled to run on the target JDK,
-#	ready for inclusion in rt.jar and tools.jar
-# dist/lib/src.zip
-#	.properties and .java files for classes in classes.jar,
-#	ready for jdk src.zip 
-
-jdk:
-	$(MAKE) -f $(SELF) \
-		MILESTONE=bootstrap \
-		TARGET_LEVEL=$(BOOTSTRAP_TARGET_LEVEL) \
-		TARGET_JAVA=$(BOOT_JAVA_HOME)/bin/java \
-		GENSRC_DIR=$(BUILD_DIR)/bootstrap/gensrc \
-		CLASSES_DIR=$(BUILD_DIR)/bootstrap/classes \
-		BIN_DIR=$(DIST_DIR)/bootstrap/bin \
-		LIB_DIR=$(DIST_DIR)/bootstrap/lib \
-		tools
-	$(MAKE) -f $(SELF) \
-		BOOT_JAVAC=$(DIST_DIR)/bootstrap/bin/javac \
-		LIB_DIR=$(BUILD_DIR)/jdk/lib \
-		$(DIST_DIR)/lib/classes.jar \
-		$(DIST_DIR)/lib/src.zip
-
-tools: $(TOOLS:%=$(LIB_DIR)/%.jar) $(TOOLS:%=$(BIN_DIR)/%)
-
-clean:
-	$(RM) -r $(BUILD_DIR)
-
-really-clean: clean
-	$(RM) -r $(DIST_DIR)
-
-jprt_product_build \
-jprt_debug_build \
-jprt_fastdebug_build: lib
-
-#-----  javac
-
-JAVAC_DIRS = \
-	javax/annotation/processing \
-	javax/lang/model \
-	javax/tools \
-        jdk/ \
-	com/sun/source \
-	com/sun/tools/javac 
-
-JAVAC_RESOURCE_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAC_DIRS)) -name SCCS -prune -o -name \*.properties -print )
-
-JAVAC_JAVA_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAC_DIRS)) -name SCCS -prune -o -name \*.java -print ) \
-	$(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAC_RESOURCE_FILES)) \
-	$(GENSRC_DIR)/com/sun/tools/javac/resources/version.java
-
-$(JAVAC_JAR): $(JAVAC_JAVA_FILES)
-	$(MKDIR) -p $(CLASSES_DIR) $(@D)
-	$(BOOT_JAVAC) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(NO_PROPRIETARY_API_WARNINGS) $(JAVAC_JAVA_FILES)
-	( $(ECHO) Main-Class: com.sun.tools.javac.Main ) > $(BUILD_DIR)/javac.mf
-	$(BOOTJAR) -cfm $@ $(BUILD_DIR)/javac.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAC_DIRS))
-
-#----- javadoc
-
-### FIXME -- javadoc has a couple of extra non-property resource files
-### that need to be included
-
-JAVADOC_DIRS = \
-	com/sun/javadoc \
-	com/sun/tools/doclets \
-	com/sun/tools/javadoc
-
-JAVADOC_RESOURCE_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVADOC_DIRS)) -name SCCS -prune -o -name \*.properties -print )
-
-JAVADOC_JAVA_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVADOC_DIRS)) -name SCCS -prune -o -name \*.java -print ) \
-	$(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVADOC_RESOURCE_FILES))
- 
-$(JAVADOC_JAR): $(JAVADOC_JAVA_FILES) $(JAVAC_JAR)
-	$(MKDIR) -p $(CLASSES_DIR) $(@D)
-	$(BOOT_JAVAC) -sourcepath "" -classpath $(JAVAC_JAR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVADOC_JAVA_FILES)
-	( $(ECHO) Main-Class: com.sun.tools.javadoc.Main ; $(ECHO) Class-Path: javac.jar ) > $(BUILD_DIR)/javadoc.mf
-	$(BOOTJAR) -cfm $@ $(BUILD_DIR)/javadoc.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVADOC_DIRS))
-
-#----- javah
-
-JAVAH_DIRS = \
-	com/sun/tools/javah
-
-JAVAH_RESOURCE_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAH_DIRS)) -name SCCS -prune -o -name \*.properties -print )
-
-JAVAH_JAVA_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAH_DIRS)) -name SCCS -prune -o -name \*.java -print ) \
-	$(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAH_RESOURCE_FILES))
- 
-$(JAVAH_JAR): $(JAVAH_JAVA_FILES) $(JAVADOC_JAR)
-	$(MKDIR) -p $(CLASSES_DIR) $(@D)
-	$(BOOT_JAVAC) -sourcepath "" -classpath $(CLASSES_DIR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVAH_JAVA_FILES)
-	( $(ECHO) Main-Class: com.sun.tools.javah.Main ; $(ECHO) Class-Path: javadoc.jar ) > $(BUILD_DIR)/javah.mf
-	$(BOOTJAR) -cfm $@ $(BUILD_DIR)/javah.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAH_DIRS))
-
-#----- javap
-
-JAVAP_DIRS = \
-	sun/tools/javap
-
-JAVAP_RESOURCE_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAP_DIRS)) -name SCCS -prune -o -name \*.properties -print )
-
-JAVAP_JAVA_FILES = \
-	$(shell find $(patsubst %,$(SRC_CLASSES_DIR)/%,$(JAVAP_DIRS)) -name SCCS -prune -o -name \*.java -print ) \
-	$(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAP_RESOURCE_FILES))
- 
-$(JAVAP_JAR): $(JAVAP_JAVA_FILES) \
-		$(patsubst $(SRC_CLASSES_DIR)/%.properties,$(GENSRC_DIR)/%.java,$(JAVAP_RESOURCE_FILES))
-	$(MKDIR) -p $(CLASSES_DIR)
-	$(BOOT_JAVAC) -sourcepath "" -classpath $(CLASSES_DIR) -d $(CLASSES_DIR) -target $(TARGET_LEVEL) $(JAVAP_JAVA_FILES)
-	( $(ECHO) Main-Class: sun.tools.javap.Main ) > $(BUILD_DIR)/javap.mf
-	$(BOOTJAR) -cfm $@ $(BUILD_DIR)/javap.mf $(patsubst %,-C $(CLASSES_DIR) %, $(JAVAP_DIRS))
-
-#-----
-
-build-tools: $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class
-
-$(GENSRC_DIR)/%.java: $(SRC_CLASSES_DIR)/%.properties $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class
-	$(MKDIR) -p $(@D)
-	$(BOOT_JAVA) -cp $(BUILDTOOLCLASSES_DIR)/CompileProperties CompileProperties $< $(patsubst $(CLASSES_DIR)/%.class,$(GENSRC_DIR)/%.java,$@)
-
-$(GENSRC_DIR)/%.java: $(GENSRC_DIR)/%.properties $(BUILDTOOLCLASSES_DIR)/CompileProperties/CompileProperties.class
-	$(MKDIR) -p $(@D)
-	$(BOOT_JAVA) -cp $(BUILDTOOLCLASSES_DIR)/CompileProperties CompileProperties $< $(patsubst $(CLASSES_DIR)/%.class,$(GENSRC_DIR)/%.java,$@)
-
-$(GENSRC_DIR)/%.properties: $(SRC_CLASSES_DIR)/%.properties-template
-	$(MKDIR) -p $(@D)
-	$(SED)  -e 's/$$(JDK_VERSION)/$(JDK_VERSION)/'  \
-		-e 's/$$(FULL_VERSION)/$(FULL_VERSION)/' \
-		-e 's/$$(RELEASE)/$(RELEASE)/' \
-		< $< > $@
-
-$(BUILDTOOLCLASSES_DIR)/%.class : $(BUILDTOOLSRC_DIR)/%.java
-	$(MKDIR) -p $(@D)
-	$(BOOT_JAVAC) -d $(@D) $<
-
-#----- all classes
-
-$(DIST_DIR)/%/classes.jar: $(JAVAC_JAR) $(JAVADOC_JAR) $(JAVAH_JAR) $(JAVAP_JAR)
-	$(MKDIR) -p $(@D)
-	$(BOOTJAR) -cf $@ -C $(CLASSES_DIR) .
-
-#----- src.zip
-
-SRC_ZIP_FILES = $(shell $(FIND) $(SRC_CLASSES_DIR) \( -name SCCS -o -name \*-template \) -prune -o -type f -print )
-
-$(DIST_DIR)/%/src.zip: $(SRC_ZIP_FILES)
-	abs_src_zip=`cd $(@D) ; pwd`/$(@F) ; \
-	( cd $(SRC_CLASSES_DIR) ; $(FIND) . \( -name SCCS -o -name \*-template \) -prune -o -type f -print | $(ZIP) -q $$abs_src_zip -@ ) ; \
-	( cd $(SRC_CLASSES_DIR) ; $(FIND) . -name SCCS -prune -o -name \*-template -print | $(SED) -e 's/-template//' ) | ( cd $(GENSRC_DIR) ; $(ZIP) -q $$abs_src_zip -@ ) 
-
-#----- bin files
-
-$(BIN_DIR)/%: $(SRC_BIN_DIR)/launcher.sh-template
-	$(MKDIR) -p $(@D)
-	$(SED) -e 's|#PROGRAM#|$(@F)|' -e 's|#TARGET_JAVA#|$(TARGET_JAVA)|' $< > $@
-	$(CHMOD) +x $@
-
-#-----
-
-findbugs: $(BUILD_DIR)/findbugs.txt
-
-$(BUILD_DIR)/findbugs.txt: $(CLASSES_JAR)
-	$(MKDIR) -p $(@D)
-	$(FINDBUGS) -textui -javahome $(BOOT_JAVA_HOME) -high -emacs -outputFile $@ $<
-
-#-----
-
-quick-check: $(patsubst %, $(DIST_LIB_DIR)/%.jar, $(TOOLS))
-	$(TESTJAVA) -jar $(JAVAC_JAR) -version
-	- $(TESTJAVA) -jar $(JAVADOC_JAR) -version
-	$(TESTJAVA) -jar $(JAVAH_JAR) -version
-	- $(TESTJAVA) -jar $(JAVAP_JAR) -version
-
-#-----
-
-.PHONY: \
-	all \
-	build \
-	build-tools \
-	clean \
-	default \
-	findbugs \
-	jprt_product_build \
-	jprt_debug_build \
-	jprt_fastdebug_build \
-	tools
-
--- a/langtools/make/build.xml	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/make/build.xml	Thu May 16 11:47:51 2013 +0100
@@ -717,6 +717,29 @@
     <target name="sjavac" depends="build-sjavac,jtreg-sjavac,findbugs-sjavac"/>
 
     <!--
+    **** crules targets.
+    -->
+
+    <target name="build-crules" depends="-def-compilecrules,-def-build-jar-with-services">
+        <compilecrules/>
+        <build-jar-with-services
+                    name="crules"
+                    includes="crules/* crules/resources/*"
+                    classes.dir="${build.toolclasses.dir}"
+                    lib.dir="${build.toolclasses.dir}"
+                    jarmainclass=""
+                    jarclasspath="crules.jar"
+                    service.type="com.sun.source.util.Plugin"
+                    service.provider="crules.MutableFieldsAnalyzer"/>
+        <build-tool name="crules"/>
+    </target>
+
+    <target name="check-coding-rules" depends="build-bootstrap-javac,-create-import-jdk-stubs,build-crules">
+        <build-classes includes="${javac.includes}"
+            plugin.options="-J-Xbootclasspath/a:${build.toolclasses.dir}/crules.jar -Xplugin:mutable_fields_analyzer" />
+    </target>
+
+    <!--
     **** Create import JDK stubs.
     -->
 
@@ -811,6 +834,31 @@
         </macrodef>
     </target>
 
+    <target name="-def-build-jar-with-services">
+        <macrodef name="build-jar-with-services">
+            <attribute name="name"/>
+            <attribute name="includes"/>
+            <attribute name="classes.dir" default="${build.classes.dir}"/>
+            <attribute name="lib.dir" default="${dist.lib.dir}"/>
+            <attribute name="jarmainclass" default="com.sun.tools.@{name}.Main"/>
+            <attribute name="jarclasspath" default=""/>
+            <attribute name="service.type" default=""/>
+            <attribute name="service.provider" default=""/>
+            <sequential>
+                <mkdir dir="${build.toolclasses.dir}"/>
+                <jar destfile="@{lib.dir}/@{name}.jar"
+                     basedir="@{classes.dir}"
+                     includes="@{includes}">
+                    <service type="@{service.type}" provider="@{service.provider}"/>
+                    <manifest>
+                        <attribute name="Main-Class" value="@{jarmainclass}"/>
+                        <attribute name="Class-Path" value="@{jarclasspath}"/>
+                    </manifest>
+                </jar>
+            </sequential>
+        </macrodef>
+    </target>
+
     <target name="-def-build-classes" depends="-def-pcompile">
         <macrodef name="build-classes">
             <attribute name="includes"/>
@@ -826,6 +874,7 @@
             <attribute name="target" default="${javac.target}"/>
             <attribute name="release" default="${release}"/>
             <attribute name="full.version" default="${full.version}"/>
+            <attribute name="plugin.options" default=""/>
             <sequential>
                 <echo level="verbose" message="build-classes: excludes=@{excludes}"/>
                 <echo level="verbose" message="build-classes: bootclasspath.opt=@{bootclasspath.opt}"/>
@@ -868,6 +917,7 @@
                     <compilerarg line="${javac.no.jdk.warnings}"/>
                     <compilerarg line="${javac.version.opt}"/>
                     <compilerarg line="${javac.lint.opts}"/>
+                    <compilerarg line="@{plugin.options}"/>
                 </javac>
                 <copy todir="@{classes.dir}" includeemptydirs="false">
                     <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
@@ -935,6 +985,32 @@
                  classpath="${build.toolclasses.dir}/"/>
     </target>
 
+    <target name="-def-compilecrules">
+        <macrodef name="compilecrules">
+            <sequential>
+                <mkdir dir="${build.toolclasses.dir}"/>
+                <javac fork="true"
+                       source="${boot.javac.source}"
+                       target="${boot.javac.target}"
+                       executable="${boot.java.home}/bin/javac"
+                       srcdir="${make.tools.dir}"
+                       includes="crules/*"
+                       destdir="${build.toolclasses.dir}/"
+                       classpath="${ant.core.lib}"
+                       bootclasspath="${boot.java.home}/jre/lib/rt.jar"
+                       includeantruntime="false">
+                    <compilerarg value="-Xbootclasspath/p:${build.bootstrap.dir}/classes"/>
+                    <compilerarg line="${javac.lint.opts}"/>
+                </javac>
+                <copy todir="${build.toolclasses.dir}/" includeemptydirs="false">
+                    <fileset dir="${make.tools.dir}">
+                        <include name="**/*.properties"/>
+                    </fileset>
+                </copy>
+            </sequential>
+        </macrodef>
+    </target>
+
     <target name="-def-genstubs" depends="build-bootstrap-javac" if="require.import.jdk.stubs">
         <mkdir dir="${build.toolclasses.dir}"/>
         <javac fork="true"
--- a/langtools/make/netbeans/langtools/nbproject/project.xml	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/make/netbeans/langtools/nbproject/project.xml	Thu May 16 11:47:51 2013 +0100
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
 
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
@@ -67,7 +67,7 @@
             </folders>
             <ide-actions>
                 <!--
- Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
 
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
@@ -96,7 +96,7 @@
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
-                <!-- 
+                <!--
  This file defines the standard actions accepted by langtools projects.
  It is normally included as an entity into a project's project.xml file.
 
@@ -104,7 +104,7 @@
    - NetBeans: Setting Up Projects
      at http://www.netbeans.org/kb/55/using-netbeans/project_setup.html
    - NetBeans: Advanced Freeform Project Configuration
-     at http://www.netbeans.org/kb/41/freeform-config.html 
+     at http://www.netbeans.org/kb/41/freeform-config.html
 -->
                 <action name="build">
                     <target>build</target>
@@ -144,7 +144,7 @@
                         </arity>
                     </context>
                 </action>
-                <!-- 
+                <!--
  Note: NetBeans does not appear to support context menu items
  on shell scripts :-(
 -->
@@ -178,7 +178,7 @@
                         </arity>
                     </context>
                 </action>
-                <!-- 
+                <!--
  Note: NetBeans does not appear to support context menu items
  on shell scripts :-(
 -->
@@ -239,10 +239,6 @@
                         <label>Build files</label>
                         <location>${root}/make</location>
                     </source-folder>
-                    <source-folder style="packages">
-                        <label>Source files</label>
-                        <location>${root}/src/share/classes</location>
-                    </source-folder>
                     <source-file>
                         <label>README</label>
                         <location>README</location>
@@ -250,7 +246,7 @@
                 </items>
                 <context-menu>
                     <!--
- Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
 
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
@@ -279,7 +275,7 @@
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
-                    <!-- 
+                    <!--
  This file defines the actions that will appear on the project's context
  menu, in the Projects viewer.
  It is normally included as an entity into a project's project.xml file.
@@ -288,7 +284,7 @@
    - NetBeans: Setting Up Projects
      at http://www.netbeans.org/kb/55/using-netbeans/project_setup.html
    - NetBeans: Advanced Freeform Project Configuration
-     at http://www.netbeans.org/kb/41/freeform-config.html 
+     at http://www.netbeans.org/kb/41/freeform-config.html
 -->
                     <ide-action name="select-tool"/>
                     <separator/>
@@ -305,11 +301,11 @@
             </view>
             <subprojects/>
         </general-data>
-        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
+        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
             <compilation-unit>
                 <package-root>${root}/src/share/classes</package-root>
                 <built-to>${root}/build/classes</built-to>
-                <source-level>1.5</source-level>
+                <source-level>1.7</source-level>
             </compilation-unit>
         </java-data>
     </configuration>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/make/tools/crules/AbstractCodingRulesAnalyzer.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,117 @@
+/*
+ * 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 crules;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.lang.model.element.TypeElement;
+import javax.tools.JavaFileObject;
+
+import com.sun.source.tree.Tree;
+import com.sun.source.util.JavacTask;
+import com.sun.source.util.Plugin;
+import com.sun.source.util.TaskEvent;
+import com.sun.source.util.TaskListener;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.api.BasicJavacTask;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Log;
+
+import static com.sun.source.util.TaskEvent.Kind;
+
+public abstract class AbstractCodingRulesAnalyzer implements Plugin {
+
+    protected Log log;
+    protected Trees trees;
+    protected TreeScanner treeVisitor;
+    protected Kind eventKind;
+    protected Messages messages;
+
+    public void init(JavacTask task, String... args) {
+        BasicJavacTask impl = (BasicJavacTask)task;
+        Context context = impl.getContext();
+        log = Log.instance(context);
+        trees = Trees.instance(task);
+        messages = new Messages();
+        task.addTaskListener(new PostAnalyzeTaskListener());
+    }
+
+    public class PostAnalyzeTaskListener implements TaskListener {
+
+        @Override
+        public void started(TaskEvent taskEvent) {}
+
+        @Override
+        public void finished(TaskEvent taskEvent) {
+            if (taskEvent.getKind().equals(eventKind)) {
+                TypeElement typeElem = taskEvent.getTypeElement();
+                Tree tree = trees.getTree(typeElem);
+                if (tree != null) {
+                    JavaFileObject prevSource = log.currentSourceFile();
+                    try {
+                        log.useSource(taskEvent.getCompilationUnit().getSourceFile());
+                        treeVisitor.scan((JCTree)tree);
+                    } finally {
+                        log.useSource(prevSource);
+                    }
+                }
+            }
+        }
+    }
+
+    class Messages {
+        ResourceBundle bundle;
+
+        Messages() {
+            String name = getClass().getPackage().getName() + ".resources.crules";
+            bundle = ResourceBundle.getBundle(name, Locale.ENGLISH);
+        }
+
+        public void error(JCTree tree, String code, Object... args) {
+            String msg = (code == null) ? (String) args[0] : localize(code, args);
+            log.error(tree, "proc.messager", msg.toString());
+        }
+
+        private String localize(String code, Object... args) {
+            String msg = bundle.getString(code);
+            if (msg == null) {
+                StringBuilder sb = new StringBuilder();
+                sb.append("message file broken: code=").append(code);
+                if (args.length > 0) {
+                    sb.append(" arguments={0}");
+                    for (int i = 1; i < args.length; i++) {
+                        sb.append(", {").append(i).append("}");
+                    }
+                }
+                msg = sb.toString();
+            }
+            return MessageFormat.format(msg, args);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,118 @@
+/*
+ * 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 crules;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.tree.TreeScanner;
+
+import static com.sun.source.util.TaskEvent.Kind;
+import static com.sun.tools.javac.code.Flags.*;
+import static com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+
+public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer {
+
+    public MutableFieldsAnalyzer() {
+        treeVisitor = new MutableFieldsVisitor();
+        eventKind = Kind.ANALYZE;
+    }
+
+    public String getName() {
+        return "mutable_fields_analyzer";
+    }
+
+    private boolean ignoreField(String className, String field) {
+        List<String> currentFieldsToIgnore =
+                classFieldsToIgnoreMap.get(className);
+        if (currentFieldsToIgnore != null) {
+            for (String fieldToIgnore : currentFieldsToIgnore) {
+                if (field.equals(fieldToIgnore)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    class MutableFieldsVisitor extends TreeScanner {
+
+        @Override
+        public void visitVarDef(JCVariableDecl tree) {
+            boolean isJavacPack = tree.sym.outermostClass().fullname.toString()
+                    .contains(packageToCheck);
+            if (isJavacPack &&
+                (tree.sym.flags() & SYNTHETIC) == 0 &&
+                tree.sym.owner.kind == Kinds.TYP) {
+                if (!ignoreField(tree.sym.owner.flatName().toString(),
+                        tree.getName().toString())) {
+                    boolean enumClass = (tree.sym.owner.flags() & ENUM) != 0;
+                    boolean nonFinalStaticEnumField =
+                            (tree.sym.flags() & (ENUM | FINAL)) == 0;
+                    boolean nonFinalStaticField =
+                            (tree.sym.flags() & STATIC) != 0 &&
+                            (tree.sym.flags() & FINAL) == 0;
+                    if (enumClass ? nonFinalStaticEnumField : nonFinalStaticField) {
+                        messages.error(tree, "crules.err.var.must.be.final", tree);
+                    }
+                }
+            }
+            super.visitVarDef(tree);
+        }
+
+    }
+
+    private static final String packageToCheck = "com.sun.tools.javac";
+
+    private static final Map<String, List<String>> classFieldsToIgnoreMap =
+                new HashMap<String, List<String>>();
+
+    static {
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.JCDiagnostic",
+                    Arrays.asList("fragmentFormatter"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.JavacMessages",
+                    Arrays.asList("defaultBundle", "defaultMessages"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.file.ZipFileIndexCache",
+                    Arrays.asList("sharedInstance"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.main.JavaCompiler",
+                    Arrays.asList("versionRB"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.code.Type",
+                    Arrays.asList("moreInfo"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.SharedNameTable",
+                    Arrays.asList("freelist"));
+        classFieldsToIgnoreMap.
+                put("com.sun.tools.javac.util.Log",
+                    Arrays.asList("useRawMessages"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/make/tools/crules/resources/crules.properties	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# 0: symbol
+crules.err.var.must.be.final=\
+    Static variable {0} must be final
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/source/util/DocSourcePositions.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.source.util;
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.tree.CompilationUnitTree;
+
+/**
+ * Provides methods to obtain the position of a DocTree within a javadoc comment.
+ * A position is defined as a simple character offset from the start of a
+ * CompilationUnit where the first character is at offset 0.
+ *
+ * @since 1.8
+ */
+@jdk.Supported
+public interface DocSourcePositions extends SourcePositions {
+
+    /**
+     * Gets the starting position of the tree within the comment within the file.  If tree is not found within
+     * file, or if the starting position is not available,
+     * return {@link javax.tools.Diagnostic#NOPOS}.
+     * The given tree should be under the given comment tree, and the given documentation
+     * comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) }
+     * for a tree under the given file.
+     * The returned position must be at the start of the yield of this tree, that
+     * is for any sub-tree of this tree, the following must hold:
+     *
+     * <p>
+     * {@code tree.getStartPosition() <= subtree.getStartPosition()} or <br>
+     * {@code tree.getStartPosition() == NOPOS} or <br>
+     * {@code subtree.getStartPosition() == NOPOS}
+     * </p>
+     *
+     * @param file CompilationUnit in which to find tree.
+     * @param comment the comment tree that encloses the tree for which the
+     *                position is being sought
+     * @param tree tree for which a position is sought.
+     * @return the start position of tree.
+     */
+    long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
+
+    /**
+     * Gets the ending position of the tree within the comment within the file.  If tree is not found within
+     * file, or if the ending position is not available,
+     * return {@link javax.tools.Diagnostic#NOPOS}.
+     * The given tree should be under the given comment tree, and the given documentation
+     * comment tree should be returned from a {@link DocTrees#getDocCommentTree(com.sun.source.util.TreePath) }
+     * for a tree under the given file.
+     * The returned position must be at the end of the yield of this tree,
+     * that is for any sub-tree of this tree, the following must hold:
+     *
+     * <p>
+     * {@code tree.getEndPosition() >= subtree.getEndPosition()} or <br>
+     * {@code tree.getEndPosition() == NOPOS} or <br>
+     * {@code subtree.getEndPosition() == NOPOS}
+     * </p>
+     *
+     * In addition, the following must hold:
+     *
+     * <p>
+     * {@code tree.getStartPosition() <= tree.getEndPosition()}  or <br>
+     * {@code tree.getStartPosition() == NOPOS} or <br>
+     * {@code tree.getEndPosition() == NOPOS}
+     * </p>
+     *
+     * @param file CompilationUnit in which to find tree.
+     * @param comment the comment tree that encloses the tree for which the
+     *                position is being sought
+     * @param tree tree for which a position is sought.
+     * @return the start position of tree.
+     */
+    long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree);
+
+}
--- a/langtools/src/share/classes/com/sun/source/util/DocTrees.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/source/util/DocTrees.java	Thu May 16 11:47:51 2013 +0100
@@ -72,6 +72,8 @@
      */
     public abstract Element getElement(TreePath path, ReferenceTree reference);
 
+    public abstract DocSourcePositions getSourcePositions();
+
     /**
      * Prints a message of the specified kind at the location of the
      * tree within the provided compilation unit
--- a/langtools/src/share/classes/com/sun/source/util/SourcePositions.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/source/util/SourcePositions.java	Thu May 16 11:47:51 2013 +0100
@@ -59,7 +59,7 @@
 
     /**
      * Gets the ending position of tree within file.  If tree is not found within
-     * file, or if the starting position is not available,
+     * file, or if the ending position is not available,
      * return {@link javax.tools.Diagnostic#NOPOS}.
      * The returned position must be at the end of the yield of this tree,
      * that is for any sub-tree of this tree, the following must hold:
--- a/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Dependencies.java	Thu May 16 11:47:51 2013 +0100
@@ -315,7 +315,7 @@
     static class SimpleLocation implements Location {
         public SimpleLocation(String name) {
             this.name = name;
-            this.className = name.replace('/', '.').replace('$', '.');
+            this.className = name.replace('/', '.');
         }
 
         public String getName() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/ReferenceFinder.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.classfile;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import com.sun.tools.classfile.Instruction.TypeKind;
+import static com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * A utility class to find where in a ClassFile references
+ * a {@link CONSTANT_Methodref_info method},
+ * a {@link CONSTANT_InterfaceMethodref_info interface method,
+ * or a {@link CONSTANT_Fieldref_info field}.
+ */
+public final class ReferenceFinder {
+    /**
+     * Filter for ReferenceFinder of what constant pool entries for reference lookup.
+     */
+    public interface Filter {
+        /**
+         * Decides if the given CPRefInfo entry should be accepted or filtered.
+         *
+         * @param cpool  ConstantPool of the ClassFile being parsed
+         * @param cpref  constant pool entry representing a reference to
+         *               a fields method, and interface method.
+         * @return {@code true} if accepted; otherwise {@code false}
+         */
+        boolean accept(ConstantPool cpool, CPRefInfo cpref);
+    }
+
+    /**
+     * Visitor of individual method of a ClassFile that references the
+     * accepted field, method, or interface method references.
+     */
+    public interface Visitor {
+        /**
+         * Invoked for a method containing one or more accepted CPRefInfo entries
+         *
+         * @param cf      ClassFile
+         * @param method  Method that does the references the accepted references
+         * @param refs    Accepted constant pool method/field reference
+         */
+        void visit(ClassFile cf, Method method, List<CPRefInfo> refConstantPool);
+    }
+
+    private final Filter filter;
+    private final Visitor visitor;
+
+    /**
+     * Constructor.
+     */
+    public ReferenceFinder(Filter filter, Visitor visitor) {
+        this.filter = Objects.requireNonNull(filter);
+        this.visitor = Objects.requireNonNull(visitor);
+    }
+
+    /**
+     * Parses a given ClassFile and invoke the visitor if there is any reference
+     * to the constant pool entries referencing field, method, or
+     * interface method that are accepted. This method will return
+     * {@code true} if there is one or more accepted constant pool entries
+     * to lookup; otherwise, it will return {@code false}.
+     *
+     * @param  cf  ClassFile
+     * @return {@code true} if the given class file is processed to lookup
+     *         references
+     * @throws ConstantPoolException if an error of the constant pool
+     */
+    public boolean parse(ClassFile cf) throws ConstantPoolException {
+        List<Integer> cprefs = new ArrayList<Integer>();
+        int index = 1;
+        for (ConstantPool.CPInfo cpInfo : cf.constant_pool.entries()) {
+            if (cpInfo.accept(cpVisitor, cf.constant_pool)) {
+                cprefs.add(index);
+            }
+            index += cpInfo.size();
+        }
+
+        if (cprefs.isEmpty()) {
+            return false;
+        }
+
+        for (Method m : cf.methods) {
+            Set<Integer> ids = new HashSet<Integer>();
+            Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code);
+            if (c_attr != null) {
+                for (Instruction instr : c_attr.getInstructions()) {
+                    int idx = instr.accept(codeVisitor, cprefs);
+                    if (idx > 0) {
+                        ids.add(idx);
+                    }
+                }
+            }
+            if (ids.size() > 0) {
+                List<CPRefInfo> refInfos = new ArrayList<CPRefInfo>(ids.size());
+                for (int id : ids) {
+                    refInfos.add(CPRefInfo.class.cast(cf.constant_pool.get(id)));
+                }
+                visitor.visit(cf, m, refInfos);
+            }
+        }
+        return true;
+    }
+
+    private ConstantPool.Visitor<Boolean,ConstantPool> cpVisitor =
+            new ConstantPool.Visitor<Boolean,ConstantPool>()
+    {
+        public Boolean visitClass(CONSTANT_Class_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, ConstantPool cpool) {
+            return filter.accept(cpool, info);
+        }
+
+        public Boolean visitMethodref(CONSTANT_Methodref_info info, ConstantPool cpool) {
+            return filter.accept(cpool, info);
+        }
+
+        public Boolean visitFieldref(CONSTANT_Fieldref_info info, ConstantPool cpool) {
+            return filter.accept(cpool, info);
+        }
+
+        public Boolean visitDouble(CONSTANT_Double_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitFloat(CONSTANT_Float_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitInteger(CONSTANT_Integer_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitLong(CONSTANT_Long_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitNameAndType(CONSTANT_NameAndType_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitMethodHandle(CONSTANT_MethodHandle_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitMethodType(CONSTANT_MethodType_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitString(CONSTANT_String_info info, ConstantPool cpool) {
+            return false;
+        }
+
+        public Boolean visitUtf8(CONSTANT_Utf8_info info, ConstantPool cpool) {
+            return false;
+        }
+    };
+
+    private Instruction.KindVisitor<Integer, List<Integer>> codeVisitor =
+            new Instruction.KindVisitor<Integer, List<Integer>>()
+    {
+        public Integer visitNoOperands(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitArrayType(Instruction instr, TypeKind kind, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitBranch(Instruction instr, int offset, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitConstantPoolRef(Instruction instr, int index, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitConstantPoolRefAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return p.contains(index) ? index : 0;
+        }
+
+        public Integer visitLocal(Instruction instr, int index, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLocalAndValue(Instruction instr, int index, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitValue(Instruction instr, int value, List<Integer> p) {
+            return 0;
+        }
+
+        public Integer visitUnknown(Instruction instr, List<Integer> p) {
+            return 0;
+        }
+    };
+}
+
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,14 +43,16 @@
 import javax.tools.JavaFileObject;
 
 import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.ReferenceTree;
 import com.sun.source.tree.CatchTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
+import com.sun.source.util.DocSourcePositions;
+import com.sun.source.util.DocTreeScanner;
 import com.sun.source.util.DocTrees;
 import com.sun.source.util.JavacTask;
-import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.code.Kinds;
@@ -76,8 +78,14 @@
 import com.sun.tools.javac.model.JavacElements;
 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
 import com.sun.tools.javac.tree.DCTree;
+import com.sun.tools.javac.tree.DCTree.DCBlockTag;
 import com.sun.tools.javac.tree.DCTree.DCDocComment;
+import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
+import com.sun.tools.javac.tree.DCTree.DCErroneous;
+import com.sun.tools.javac.tree.DCTree.DCIdentifier;
+import com.sun.tools.javac.tree.DCTree.DCParam;
 import com.sun.tools.javac.tree.DCTree.DCReference;
+import com.sun.tools.javac.tree.DCTree.DCText;
 import com.sun.tools.javac.tree.EndPosTable;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -94,6 +102,7 @@
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
 import com.sun.tools.javac.util.Pair;
+import com.sun.tools.javac.util.Position;
 import static com.sun.tools.javac.code.TypeTag.*;
 
 /**
@@ -166,8 +175,8 @@
             javacTaskImpl = (JavacTaskImpl) t;
     }
 
-    public SourcePositions getSourcePositions() {
-        return new SourcePositions() {
+    public DocSourcePositions getSourcePositions() {
+        return new DocSourcePositions() {
                 public long getStartPosition(CompilationUnitTree file, Tree tree) {
                     return TreeInfo.getStartPos((JCTree) tree);
                 }
@@ -176,9 +185,80 @@
                     EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions;
                     return TreeInfo.getEndPos((JCTree) tree, endPosTable);
                 }
+
+                public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
+                    return ((DCTree) tree).getSourcePosition((DCDocComment) comment);
+                }
+                @SuppressWarnings("fallthrough")
+                public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) {
+                    DCDocComment dcComment = (DCDocComment) comment;
+                    if (tree instanceof DCEndPosTree) {
+                        int endPos = ((DCEndPosTree) tree).getEndPos(dcComment);
+
+                        if (endPos != Position.NOPOS) {
+                            return endPos;
+                        }
+                    }
+                    int correction = 0;
+                    switch (tree.getKind()) {
+                        case TEXT:
+                            DCText text = (DCText) tree;
+
+                            return dcComment.comment.getSourcePos(text.pos + text.text.length());
+                        case ERRONEOUS:
+                            DCErroneous err = (DCErroneous) tree;
+
+                            return dcComment.comment.getSourcePos(err.pos + err.body.length());
+                        case IDENTIFIER:
+                            DCIdentifier ident = (DCIdentifier) tree;
+
+                            return dcComment.comment.getSourcePos(ident.pos + (ident.name != names.error ? ident.name.length() : 0));
+                        case PARAM:
+                            DCParam param = (DCParam) tree;
+
+                            if (param.isTypeParameter && param.getDescription().isEmpty()) {
+                                correction = 1;
+                            }
+                        case AUTHOR: case DEPRECATED: case RETURN: case SEE:
+                        case SERIAL: case SERIAL_DATA: case SERIAL_FIELD: case SINCE:
+                        case THROWS: case UNKNOWN_BLOCK_TAG: case VERSION: {
+                            DocTree last = getLastChild(tree);
+
+                            if (last != null) {
+                                return getEndPosition(file, comment, last) + correction;
+                            }
+
+                            DCBlockTag block = (DCBlockTag) tree;
+
+                            return dcComment.comment.getSourcePos(block.pos + block.getTagName().length() + 1);
+                        }
+                        default:
+                            DocTree last = getLastChild(tree);
+
+                            if (last != null) {
+                                return getEndPosition(file, comment, last);
+                            }
+                            break;
+                    }
+
+                    return Position.NOPOS;
+                }
             };
     }
 
+    private DocTree getLastChild(DocTree tree) {
+        final DocTree[] last = new DocTree[] {null};
+
+        tree.accept(new DocTreeScanner<Void, Void>() {
+            @Override public Void scan(DocTree node, Void p) {
+                if (node != null) last[0] = node;
+                return null;
+            }
+        }, null);
+
+        return last[0];
+    }
+
     public JCClassDecl getTree(TypeElement element) {
         return (JCClassDecl) getTree((Element) element);
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Thu May 16 11:47:51 2013 +0100
@@ -465,19 +465,12 @@
      * This is the implementation for {@code
      * javax.lang.model.element.Element.getAnnotationMirrors()}.
      */
-    public final List<? extends AnnotationMirror> getAnnotationMirrors() {
+    @Override
+    public List<Attribute.Compound> getAnnotationMirrors() {
         return getRawAttributes();
     }
 
     /**
-     * TODO: Should there be a {@code
-     * javax.lang.model.element.Element.getTypeAnnotationMirrors()}.
-     */
-    public final List<Attribute.TypeCompound> getTypeAnnotationMirrors() {
-        return getRawTypeAttributes();
-    }
-
-    /**
      * @deprecated this method should never be used by javac internally.
      */
     @Deprecated
@@ -657,6 +650,24 @@
         }
 
         @Override
+        public List<Attribute.Compound> getAnnotationMirrors() {
+            return onlyTypeVariableAnnotations(owner.getRawTypeAttributes());
+        }
+
+        private List<Attribute.Compound> onlyTypeVariableAnnotations(
+                List<Attribute.TypeCompound> candidates) {
+            // Declaration annotations on TypeParameters are stored in type attributes
+            List<Attribute.Compound> res = List.nil();
+            for (Attribute.TypeCompound a : candidates) {
+                if (a.position.type == TargetType.CLASS_TYPE_PARAMETER ||
+                    a.position.type == TargetType.METHOD_TYPE_PARAMETER)
+                    res = res.prepend(a);
+            }
+
+            return res = res.reverse();
+        }
+
+        @Override
         public <R, P> R accept(ElementVisitor<R, P> v, P p) {
             return v.visitTypeParameter(this, p);
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Thu May 16 11:47:51 2013 +0100
@@ -206,7 +206,7 @@
                     sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
                 // Make sure all type annotations from the symbol are also
                 // on the owner.
-                sym.owner.annotations.appendUniqueTypes(sym.getTypeAnnotationMirrors());
+                sym.owner.annotations.appendUniqueTypes(sym.getRawTypeAttributes());
             }
         }
 
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu May 16 11:47:51 2013 +0100
@@ -1078,7 +1078,8 @@
                 mask = MethodFlags;
             }
             // Imply STRICTFP if owner has STRICTFP set.
-            if (((flags|implicit) & Flags.ABSTRACT) == 0)
+            if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
+                ((flags) & Flags.DEFAULT) != 0)
                 implicit |= sym.owner.flags_field & STRICTFP;
             break;
         case TYP:
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Thu May 16 11:47:51 2013 +0100
@@ -35,7 +35,6 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 
 import com.sun.tools.javac.code.Symbol.*;
-import com.sun.tools.javac.comp.Resolve;
 import com.sun.tools.javac.tree.JCTree.*;
 
 import static com.sun.tools.javac.code.Flags.*;
@@ -277,6 +276,15 @@
     }
 
     /**
+     * Utility method to reset several Bits instances.
+     */
+    private void resetBits(Bits... bits) {
+        for (Bits b : bits) {
+            b.reset();
+        }
+    }
+
+    /**
      * Base visitor class for all visitors implementing dataflow analysis logic.
      * This class define the shared logic for handling jumps (break/continue statements).
      */
@@ -1294,11 +1302,11 @@
 
         /** The set of definitely assigned variables.
          */
-        Bits inits;
+        final Bits inits;
 
         /** The set of definitely unassigned variables.
          */
-        Bits uninits;
+        final Bits uninits;
 
         /** The set of variables that are definitely unassigned everywhere
          *  in current try block. This variable is maintained lazily; it is
@@ -1308,15 +1316,15 @@
          *  anywhere in current try block, intersect uninitsTry and
          *  uninits.
          */
-        Bits uninitsTry;
+        final Bits uninitsTry;
 
         /** When analyzing a condition, inits and uninits are null.
          *  Instead we have:
          */
-        Bits initsWhenTrue;
-        Bits initsWhenFalse;
-        Bits uninitsWhenTrue;
-        Bits uninitsWhenFalse;
+        final Bits initsWhenTrue;
+        final Bits initsWhenFalse;
+        final Bits uninitsWhenTrue;
+        final Bits uninitsWhenFalse;
 
         /** A mapping from addresses to variable symbols.
          */
@@ -1348,15 +1356,25 @@
         /** The starting position of the analysed tree */
         int startPos;
 
+        AssignAnalyzer() {
+            inits = new Bits();
+            uninits = new Bits();
+            uninitsTry = new Bits();
+            initsWhenTrue = new Bits(true);
+            initsWhenFalse = new Bits(true);
+            uninitsWhenTrue = new Bits(true);
+            uninitsWhenFalse = new Bits(true);
+        }
+
         class AssignPendingExit extends BaseAnalyzer.PendingExit {
 
-            Bits exit_inits;
-            Bits exit_uninits;
+            final Bits exit_inits = new Bits(true);
+            final Bits exit_uninits = new Bits(true);
 
-            AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
+            AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
                 super(tree);
-                this.exit_inits = inits.dup();
-                this.exit_uninits = uninits.dup();
+                this.exit_inits.assign(inits);
+                this.exit_uninits.assign(uninits);
             }
 
             void resolveJump() {
@@ -1476,19 +1494,20 @@
         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
          */
         void split(boolean setToNull) {
-            initsWhenFalse = inits.dup();
-            uninitsWhenFalse = uninits.dup();
-            initsWhenTrue = inits;
-            uninitsWhenTrue = uninits;
-            if (setToNull)
-                inits = uninits = null;
+            initsWhenFalse.assign(inits);
+            uninitsWhenFalse.assign(uninits);
+            initsWhenTrue.assign(inits);
+            uninitsWhenTrue.assign(uninits);
+            if (setToNull) {
+                resetBits(inits, uninits);
+            }
         }
 
         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
          */
         void merge() {
-            inits = initsWhenFalse.andSet(initsWhenTrue);
-            uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
+            inits.assign(initsWhenFalse.andSet(initsWhenTrue));
+            uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
         }
 
     /* ************************************************************************
@@ -1501,7 +1520,7 @@
         void scanExpr(JCTree tree) {
             if (tree != null) {
                 scan(tree);
-                if (inits == null) merge();
+                if (inits.isReset()) merge();
             }
         }
 
@@ -1518,28 +1537,29 @@
          */
         void scanCond(JCTree tree) {
             if (tree.type.isFalse()) {
-                if (inits == null) merge();
-                initsWhenTrue = inits.dup();
+                if (inits.isReset()) merge();
+                initsWhenTrue.assign(inits);
                 initsWhenTrue.inclRange(firstadr, nextadr);
-                uninitsWhenTrue = uninits.dup();
+                uninitsWhenTrue.assign(uninits);
                 uninitsWhenTrue.inclRange(firstadr, nextadr);
-                initsWhenFalse = inits;
-                uninitsWhenFalse = uninits;
+                initsWhenFalse.assign(inits);
+                uninitsWhenFalse.assign(uninits);
             } else if (tree.type.isTrue()) {
-                if (inits == null) merge();
-                initsWhenFalse = inits.dup();
+                if (inits.isReset()) merge();
+                initsWhenFalse.assign(inits);
                 initsWhenFalse.inclRange(firstadr, nextadr);
-                uninitsWhenFalse = uninits.dup();
+                uninitsWhenFalse.assign(uninits);
                 uninitsWhenFalse.inclRange(firstadr, nextadr);
-                initsWhenTrue = inits;
-                uninitsWhenTrue = uninits;
+                initsWhenTrue.assign(inits);
+                uninitsWhenTrue.assign(uninits);
             } else {
                 scan(tree);
-                if (inits != null)
+                if (!inits.isReset())
                     split(tree.type != syms.unknownType);
             }
-            if (tree.type != syms.unknownType)
-                inits = uninits = null;
+            if (tree.type != syms.unknownType) {
+                resetBits(inits, uninits);
+            }
         }
 
         /* ------------ Visitor methods for various sorts of trees -------------*/
@@ -1619,8 +1639,8 @@
         public void visitMethodDef(JCMethodDecl tree) {
             if (tree.body == null) return;
 
-            Bits initsPrev = inits.dup();
-            Bits uninitsPrev = uninits.dup();
+            final Bits initsPrev = new Bits(inits);
+            final Bits uninitsPrev = new Bits(uninits);
             int nextadrPrev = nextadr;
             int firstadrPrev = firstadr;
             int returnadrPrev = returnadr;
@@ -1658,14 +1678,14 @@
                     exits = exits.tail;
                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
                     if (isInitialConstructor) {
-                        inits = exit.exit_inits;
+                        inits.assign(exit.exit_inits);
                         for (int i = firstadr; i < nextadr; i++)
                             checkInit(exit.tree.pos(), vars[i]);
                     }
                 }
             } finally {
-                inits = initsPrev;
-                uninits = uninitsPrev;
+                inits.assign(initsPrev);
+                uninits.assign(uninitsPrev);
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 returnadr = returnadrPrev;
@@ -1698,31 +1718,31 @@
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
                 scanCond(tree.cond);
                 if (!flowKind.isFinal()) {
-                    initsSkip = initsWhenFalse;
-                    uninitsSkip = uninitsWhenFalse;
+                    initsSkip.assign(initsWhenFalse);
+                    uninitsSkip.assign(uninitsWhenFalse);
                 }
                 if (log.nerrors !=  prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
+                    new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
                     break;
-                inits = initsWhenTrue;
-                uninits = uninitsEntry.andSet(uninitsWhenTrue);
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
@@ -1730,34 +1750,34 @@
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
-            Bits uninitsEntry = uninits.dup();
+            final Bits uninitsEntry = new Bits(uninits);
             uninitsEntry.excludeFrom(nextadr);
             do {
                 scanCond(tree.cond);
                 if (!flowKind.isFinal()) {
-                    initsSkip = initsWhenFalse;
-                    uninitsSkip = uninitsWhenFalse;
+                    initsSkip.assign(initsWhenFalse) ;
+                    uninitsSkip.assign(uninitsWhenFalse);
                 }
-                inits = initsWhenTrue;
-                uninits = uninitsWhenTrue;
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsWhenTrue);
                 scan(tree.body);
                 resolveContinues(tree);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
@@ -1767,25 +1787,25 @@
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.init);
-            Bits initsSkip = null;
-            Bits uninitsSkip = null;
+            final Bits initsSkip = new Bits(true);
+            final Bits uninitsSkip = new Bits(true);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 if (tree.cond != null) {
                     scanCond(tree.cond);
                     if (!flowKind.isFinal()) {
-                        initsSkip = initsWhenFalse;
-                        uninitsSkip = uninitsWhenFalse;
+                        initsSkip.assign(initsWhenFalse);
+                        uninitsSkip.assign(uninitsWhenFalse);
                     }
-                    inits = initsWhenTrue;
-                    uninits = uninitsWhenTrue;
+                    inits.assign(initsWhenTrue);
+                    uninits.assign(uninitsWhenTrue);
                 } else if (!flowKind.isFinal()) {
-                    initsSkip = inits.dup();
+                    initsSkip.assign(inits);
                     initsSkip.inclRange(firstadr, nextadr);
-                    uninitsSkip = uninits.dup();
+                    uninitsSkip.assign(uninits);
                     uninitsSkip.inclRange(firstadr, nextadr);
                 }
                 scan(tree.body);
@@ -1793,16 +1813,16 @@
                 scan(tree.step);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits = initsSkip;
-            uninits = uninitsSkip;
+            inits.assign(initsSkip);
+            uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
@@ -1815,27 +1835,27 @@
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.expr);
-            Bits initsStart = inits.dup();
-            Bits uninitsStart = uninits.dup();
+            final Bits initsStart = new Bits(inits);
+            final Bits uninitsStart = new Bits(uninits);
 
             letInit(tree.pos(), tree.var.sym);
             pendingExits = new ListBuffer<AssignPendingExit>();
             int prevErrors = log.nerrors;
             do {
-                Bits uninitsEntry = uninits.dup();
+                final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
                 if (log.nerrors != prevErrors ||
                     flowKind.isFinal() ||
-                    uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
-                uninits = uninitsEntry.andSet(uninits);
+                uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits = initsStart;
-            uninits = uninitsStart.andSet(uninits);
+            inits.assign(initsStart);
+            uninits.assign(uninitsStart.andSet(uninits));
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
@@ -1852,12 +1872,12 @@
             pendingExits = new ListBuffer<AssignPendingExit>();
             int nextadrPrev = nextadr;
             scanExpr(tree.selector);
-            Bits initsSwitch = inits;
-            Bits uninitsSwitch = uninits.dup();
+            final Bits initsSwitch = new Bits(inits);
+            final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-                inits = initsSwitch.dup();
-                uninits = uninits.andSet(uninitsSwitch);
+                inits.assign(initsSwitch);
+                uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
                 if (c.pat == null)
                     hasDefault = true;
@@ -1875,8 +1895,8 @@
         }
         // where
             /** Add any variables defined in stats to inits and uninits. */
-            private void addVars(List<JCStatement> stats, Bits inits,
-                                        Bits uninits) {
+            private void addVars(List<JCStatement> stats, final Bits inits,
+                                        final Bits uninits) {
                 for (;stats.nonEmpty(); stats = stats.tail) {
                     JCTree stat = stats.head;
                     if (stat.hasTag(VARDEF)) {
@@ -1889,11 +1909,11 @@
 
         public void visitTry(JCTry tree) {
             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
-            Bits uninitsTryPrev = uninitsTry;
+            final Bits uninitsTryPrev = new Bits(uninitsTry);
             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
             pendingExits = new ListBuffer<AssignPendingExit>();
-            Bits initsTry = inits.dup();
-            uninitsTry = uninits.dup();
+            final Bits initsTry = new Bits(inits);
+            uninitsTry.assign(uninits);
             for (JCTree resource : tree.resources) {
                 if (resource instanceof JCVariableDecl) {
                     JCVariableDecl vdecl = (JCVariableDecl) resource;
@@ -1908,8 +1928,8 @@
             }
             scan(tree.body);
             uninitsTry.andSet(uninits);
-            Bits initsEnd = inits;
-            Bits uninitsEnd = uninits;
+            final Bits initsEnd = new Bits(inits);
+            final Bits uninitsEnd = new Bits(uninits);
             int nextadrCatch = nextadr;
 
             if (!resourceVarDecls.isEmpty() &&
@@ -1925,8 +1945,8 @@
 
             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl param = l.head.param;
-                inits = initsTry.dup();
-                uninits = uninitsTry.dup();
+                inits.assign(initsTry);
+                uninits.assign(uninitsTry);
                 scan(param);
                 inits.incl(param.sym.adr);
                 uninits.excl(param.sym.adr);
@@ -1936,8 +1956,8 @@
                 nextadr = nextadrCatch;
             }
             if (tree.finalizer != null) {
-                inits = initsTry.dup();
-                uninits = uninitsTry.dup();
+                inits.assign(initsTry);
+                uninits.assign(uninitsTry);
                 ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 scan(tree.finalizer);
@@ -1958,8 +1978,8 @@
                     inits.orSet(initsEnd);
                 }
             } else {
-                inits = initsEnd;
-                uninits = uninitsEnd;
+                inits.assign(initsEnd);
+                uninits.assign(uninitsEnd);
                 ListBuffer<AssignPendingExit> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 while (exits.nonEmpty()) pendingExits.append(exits.next());
@@ -1969,10 +1989,10 @@
 
         public void visitConditional(JCConditional tree) {
             scanCond(tree.cond);
-            Bits initsBeforeElse = initsWhenFalse;
-            Bits uninitsBeforeElse = uninitsWhenFalse;
-            inits = initsWhenTrue;
-            uninits = uninitsWhenTrue;
+            final Bits initsBeforeElse = new Bits(initsWhenFalse);
+            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
+            inits.assign(initsWhenTrue);
+            uninits.assign(uninitsWhenTrue);
             if (tree.truepart.type.hasTag(BOOLEAN) &&
                 tree.falsepart.type.hasTag(BOOLEAN)) {
                 // if b and c are boolean valued, then
@@ -1980,12 +2000,12 @@
                 //    v is (un)assigned after b when true and
                 //    v is (un)assigned after c when true
                 scanCond(tree.truepart);
-                Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
-                Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
-                Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
-                Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
+                final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
+                final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
+                final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scanCond(tree.falsepart);
                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
@@ -1993,10 +2013,10 @@
                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
             } else {
                 scanExpr(tree.truepart);
-                Bits initsAfterThen = inits.dup();
-                Bits uninitsAfterThen = uninits.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThen = new Bits(inits);
+                final Bits uninitsAfterThen = new Bits(uninits);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scanExpr(tree.falsepart);
                 inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
@@ -2005,16 +2025,16 @@
 
         public void visitIf(JCIf tree) {
             scanCond(tree.cond);
-            Bits initsBeforeElse = initsWhenFalse;
-            Bits uninitsBeforeElse = uninitsWhenFalse;
-            inits = initsWhenTrue;
-            uninits = uninitsWhenTrue;
+            final Bits initsBeforeElse = new Bits(initsWhenFalse);
+            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
+            inits.assign(initsWhenTrue);
+            uninits.assign(uninitsWhenTrue);
             scan(tree.thenpart);
             if (tree.elsepart != null) {
-                Bits initsAfterThen = inits.dup();
-                Bits uninitsAfterThen = uninits.dup();
-                inits = initsBeforeElse;
-                uninits = uninitsBeforeElse;
+                final Bits initsAfterThen = new Bits(inits);
+                final Bits uninitsAfterThen = new Bits(uninits);
+                inits.assign(initsBeforeElse);
+                uninits.assign(uninitsBeforeElse);
                 scan(tree.elsepart);
                 inits.andSet(initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
@@ -2055,8 +2075,8 @@
 
         @Override
         public void visitLambda(JCLambda tree) {
-            Bits prevUninits = uninits;
-            Bits prevInits = inits;
+            final Bits prevUninits = new Bits(uninits);
+            final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
             ListBuffer<AssignPendingExit> prevPending = pendingExits;
             try {
@@ -2076,8 +2096,8 @@
             }
             finally {
                 returnadr = returnadrPrev;
-                uninits = prevUninits;
-                inits = prevInits;
+                uninits.assign(prevUninits);
+                inits.assign(prevInits);
                 pendingExits = prevPending;
             }
         }
@@ -2088,17 +2108,17 @@
         }
 
         public void visitAssert(JCAssert tree) {
-            Bits initsExit = inits.dup();
-            Bits uninitsExit = uninits.dup();
+            final Bits initsExit = new Bits(inits);
+            final Bits uninitsExit = new Bits(uninits);
             scanCond(tree.cond);
             uninitsExit.andSet(uninitsWhenTrue);
             if (tree.detail != null) {
-                inits = initsWhenFalse;
-                uninits = uninitsWhenFalse;
+                inits.assign(initsWhenFalse);
+                uninits.assign(uninitsWhenFalse);
                 scanExpr(tree.detail);
             }
-            inits = initsExit;
-            uninits = uninitsExit;
+            inits.assign(initsExit);
+            uninits.assign(uninitsExit);
         }
 
         public void visitAssign(JCAssign tree) {
@@ -2120,12 +2140,12 @@
             switch (tree.getTag()) {
             case NOT:
                 scanCond(tree.arg);
-                Bits t = initsWhenFalse;
-                initsWhenFalse = initsWhenTrue;
-                initsWhenTrue = t;
-                t = uninitsWhenFalse;
-                uninitsWhenFalse = uninitsWhenTrue;
-                uninitsWhenTrue = t;
+                final Bits t = new Bits(initsWhenFalse);
+                initsWhenFalse.assign(initsWhenTrue);
+                initsWhenTrue.assign(t);
+                t.assign(uninitsWhenFalse);
+                uninitsWhenFalse.assign(uninitsWhenTrue);
+                uninitsWhenTrue.assign(t);
                 break;
             case PREINC: case POSTINC:
             case PREDEC: case POSTDEC:
@@ -2141,20 +2161,20 @@
             switch (tree.getTag()) {
             case AND:
                 scanCond(tree.lhs);
-                Bits initsWhenFalseLeft = initsWhenFalse;
-                Bits uninitsWhenFalseLeft = uninitsWhenFalse;
-                inits = initsWhenTrue;
-                uninits = uninitsWhenTrue;
+                final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
+                final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
+                inits.assign(initsWhenTrue);
+                uninits.assign(uninitsWhenTrue);
                 scanCond(tree.rhs);
                 initsWhenFalse.andSet(initsWhenFalseLeft);
                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
                 break;
             case OR:
                 scanCond(tree.lhs);
-                Bits initsWhenTrueLeft = initsWhenTrue;
-                Bits uninitsWhenTrueLeft = uninitsWhenTrue;
-                inits = initsWhenFalse;
-                uninits = uninitsWhenFalse;
+                final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
+                final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
+                inits.assign(initsWhenFalse);
+                uninits.assign(uninitsWhenFalse);
                 scanCond(tree.rhs);
                 initsWhenTrue.andSet(initsWhenTrueLeft);
                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
@@ -2200,11 +2220,7 @@
                 attrEnv = env;
                 Flow.this.make = make;
                 startPos = tree.pos().getStartPosition();
-                inits = new Bits();
-                uninits = new Bits();
-                uninitsTry = new Bits();
-                initsWhenTrue = initsWhenFalse =
-                    uninitsWhenTrue = uninitsWhenFalse = null;
+
                 if (vars == null)
                     vars = new VarSymbol[32];
                 else
@@ -2219,9 +2235,8 @@
             } finally {
                 // note that recursive invocations of this method fail hard
                 startPos = -1;
-                inits = uninits = uninitsTry = null;
-                initsWhenTrue = initsWhenFalse =
-                    uninitsWhenTrue = uninitsWhenFalse = null;
+                resetBits(inits, uninits, uninitsTry, initsWhenTrue,
+                        initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
                 if (vars != null) for (int i=0; i<vars.length; i++)
                     vars[i] = null;
                 firstadr = 0;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu May 16 11:47:51 2013 +0100
@@ -40,10 +40,9 @@
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.Type.ClassType;
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzer.*;
+import com.sun.tools.javac.comp.LambdaToMethod.LambdaAnalyzerPreprocessor.*;
 import com.sun.tools.javac.comp.Lower.BasicFreeVarCollector;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.util.*;
@@ -81,7 +80,7 @@
     private Env<AttrContext> attrEnv;
 
     /** the analyzer scanner */
-    private LambdaAnalyzer analyzer;
+    private LambdaAnalyzerPreprocessor analyzer;
 
     /** map from lambda trees to translation contexts */
     private Map<JCTree, TranslationContext<?>> contextMap;
@@ -156,7 +155,7 @@
         make = TreeMaker.instance(context);
         types = Types.instance(context);
         transTypes = TransTypes.instance(context);
-        analyzer = new LambdaAnalyzer();
+        analyzer = new LambdaAnalyzerPreprocessor();
     }
     // </editor-fold>
 
@@ -206,7 +205,7 @@
     public void visitClassDef(JCClassDecl tree) {
         if (tree.sym.owner.kind == PCK) {
             //analyze class
-            analyzer.analyzeClass(tree);
+            tree = analyzer.analyzeAndPreprocessClass(tree);
         }
         KlassInfo prevKlassInfo = kInfo;
         try {
@@ -531,16 +530,25 @@
     /** Make an attributed class instance creation expression.
      *  @param ctype    The class type.
      *  @param args     The constructor arguments.
+     *  @param cons     The constructor symbol
      */
-    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
+    JCNewClass makeNewClass(Type ctype, List<JCExpression> args, Symbol cons) {
         JCNewClass tree = make.NewClass(null,
             null, make.QualIdent(ctype.tsym), args, null);
-        tree.constructor = rs.resolveConstructor(
-            null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil());
+        tree.constructor = cons;
         tree.type = ctype;
         return tree;
     }
 
+    /** Make an attributed class instance creation expression.
+     *  @param ctype    The class type.
+     *  @param args     The constructor arguments.
+     */
+    JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
+        return makeNewClass(ctype, args,
+                rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.<Type>nil()));
+     }
+
     private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym,
             DiagnosticPosition pos, List<Object> staticArgs, MethodType indyType) {
         String functionalInterfaceClass = classSig(targetType);
@@ -1019,8 +1027,9 @@
      * This visitor collects information about translation of a lambda expression.
      * More specifically, it keeps track of the enclosing contexts and captured locals
      * accessed by the lambda being translated (as well as other useful info).
+     * It also translates away problems for LambdaToMethod.
      */
-    class LambdaAnalyzer extends TreeScanner {
+    class LambdaAnalyzerPreprocessor extends TreeTranslator {
 
         /** the frame stack - used to reconstruct translation info about enclosing scopes */
         private List<Frame> frameStack;
@@ -1047,10 +1056,10 @@
         private Map<ClassSymbol, Symbol> clinits =
                 new HashMap<ClassSymbol, Symbol>();
 
-        private void analyzeClass(JCClassDecl tree) {
+        private JCClassDecl analyzeAndPreprocessClass(JCClassDecl tree) {
             frameStack = List.nil();
             localClassDefs = new HashMap<Symbol, JCClassDecl>();
-            scan(tree);
+            return translate(tree);
         }
 
         @Override
@@ -1154,7 +1163,7 @@
                     frameStack.head.addLocal(param.sym);
                 }
                 contextMap.put(tree, context);
-                scan(tree.body);
+                super.visitLambda(tree);
                 context.complete();
             }
             finally {
@@ -1220,12 +1229,47 @@
                     };
                     fvc.scan(localCDef);
                 }
-            }
+        }
 
+        /**
+         * Method references to local class constructors, may, if the local
+         * class references local variables, have implicit constructor
+         * parameters added in Lower; As a result, the invokedynamic bootstrap
+         * information added in the LambdaToMethod pass will have the wrong
+         * signature. Hooks between Lower and LambdaToMethod have been added to
+         * handle normal "new" in this case. This visitor converts potentially
+         * effected method references into a lambda containing a normal "new" of
+         * the class.
+         *
+         * @param tree
+         */
         @Override
         public void visitReference(JCMemberReference tree) {
-            scan(tree.getQualifierExpression());
-            contextMap.put(tree, makeReferenceContext(tree));
+            if (tree.getMode() == ReferenceMode.NEW
+                    && tree.kind != ReferenceKind.ARRAY_CTOR
+                    && tree.sym.owner.isLocal()) {
+                MethodSymbol consSym = (MethodSymbol) tree.sym;
+                List<Type> ptypes = ((MethodType) consSym.type).getParameterTypes();
+                Type classType = consSym.owner.type;
+
+                // Make new-class call
+                List<JCVariableDecl> params = make.Params(ptypes, owner());
+                JCNewClass nc = makeNewClass(classType, make.Idents(params));
+                nc.pos = tree.pos;
+
+                // Make lambda holding the new-class call
+                JCLambda slam = make.Lambda(params, nc);
+                slam.descriptorType = tree.descriptorType;
+                slam.targets = tree.targets;
+                slam.type = tree.type;
+                slam.pos = tree.pos;
+
+                // Now it is a lambda, process as such
+                visitLambda(slam);
+            } else {
+                super.visitReference(tree);
+                contextMap.put(tree, makeReferenceContext(tree));
+            }
         }
 
         @Override
@@ -1240,10 +1284,8 @@
                     }
                     localContext = localContext.prev;
                 }
-                scan(tree.selected);
-            } else {
-                super.visitSelect(tree);
             }
+            super.visitSelect(tree);
         }
 
         @Override
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java	Thu May 16 11:47:51 2013 +0100
@@ -1647,7 +1647,7 @@
         State dup() {
             try {
                 State state = (State)super.clone();
-                state.defined = defined.dup();
+                state.defined = new Bits(defined);
                 state.stack = stack.clone();
                 if (locks != null) state.locks = locks.clone();
                 if (debugCode) {
@@ -1775,7 +1775,7 @@
         }
 
         State join(State other) {
-            defined = defined.andSet(other.defined);
+            defined.andSet(other.defined);
             Assert.check(stacksize == other.stacksize
                     && nlocks == other.nlocks);
             for (int i=0; i<stacksize; ) {
@@ -1887,7 +1887,7 @@
     /** Set the current variable defined state. */
     public void setDefined(Bits newDefined) {
         if (alive && newDefined != state.defined) {
-            Bits diff = state.defined.dup().xorSet(newDefined);
+            Bits diff = new Bits(state.defined).xorSet(newDefined);
             for (int adr = diff.nextBit(0);
                  adr >= 0;
                  adr = diff.nextBit(adr+1)) {
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacAnnoConstructs.java	Thu May 16 11:47:51 2013 +0100
@@ -33,10 +33,13 @@
 import com.sun.tools.javac.code.Kinds;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.TypeVariableSymbol;
+import com.sun.tools.javac.code.TargetType;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.AnnotatedType;
 import com.sun.tools.javac.util.ListBuffer;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
+import com.sun.tools.javac.util.List;
 
 /**
  * Utility methods for operating on annotated constructs.
@@ -61,8 +64,12 @@
             throw new IllegalArgumentException("Not an annotation type: "
                                                + annoType);
         Attribute.Compound c;
-        if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) {
+        if (annotated.kind == Kinds.TYP &&
+                annotated instanceof ClassSymbol) {
             c = getAttributeOnClass((ClassSymbol)annotated, annoType);
+        } else if (annotated.kind == Kinds.TYP &&
+                   annotated instanceof TypeVariableSymbol) {
+            c = getAttributeOnTypeVariable((TypeVariableSymbol)annotated, annoType);
         } else {
             c = getAttribute(annotated, annoType);
         }
@@ -83,6 +90,24 @@
     }
 
     // Helper to getAnnotation[s]
+    private static <A extends Annotation> Attribute.Compound
+            getAttributeOnTypeVariable(TypeVariableSymbol annotated, Class<A> annoType) {
+        String name = annoType.getName();
+
+        // Declaration annotations on type variables are stored in type attributes
+        // on the owner of the TypeVariableSymbol
+        List<Attribute.Compound> res = List.nil();
+        List<Attribute.TypeCompound> candidates = annotated.owner.getRawTypeAttributes();
+        for (Attribute.TypeCompound anno : candidates)
+            if (anno.position.type == TargetType.CLASS_TYPE_PARAMETER ||
+                    anno.position.type == TargetType.METHOD_TYPE_PARAMETER)
+                if (name.equals(anno.type.tsym.flatName().toString()))
+                    return anno;
+
+        return null;
+    }
+
+    // Helper to getAnnotation[s]
     private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated,
                                                                 Class<A> annoType) {
         boolean inherited = annoType.isAnnotationPresent(Inherited.class);
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java	Thu May 16 11:47:51 2013 +0100
@@ -402,9 +402,10 @@
      * @param e  the element being examined
      * @return all annotations of the element
      */
+    @Override
     public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
         Symbol sym = cast(Symbol.class, e);
-        List<Attribute.Compound> annos = sym.getRawAttributes();
+        List<Attribute.Compound> annos = sym.getAnnotationMirrors();
         while (sym.getKind() == ElementKind.CLASS) {
             Type sup = ((ClassSymbol) sym).getSuperclass();
             if (!sup.hasTag(CLASS) || sup.isErroneous() ||
@@ -413,7 +414,7 @@
             }
             sym = sup.tsym;
             List<Attribute.Compound> oldAnnos = annos;
-            List<Attribute.Compound> newAnnos = sym.getRawAttributes();
+            List<Attribute.Compound> newAnnos = sym.getAnnotationMirrors();
             for (Attribute.Compound anno : newAnnos) {
                 if (isInherited(anno.type) &&
                         !containsAnnoOfType(oldAnnos, anno.type)) {
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Thu May 16 11:47:51 2013 +0100
@@ -41,6 +41,7 @@
 import com.sun.tools.javac.tree.DCTree.DCAttribute;
 import com.sun.tools.javac.tree.DCTree.DCDocComment;
 import com.sun.tools.javac.tree.DCTree.DCEndElement;
+import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
 import com.sun.tools.javac.tree.DCTree.DCErroneous;
 import com.sun.tools.javac.tree.DCTree.DCIdentifier;
 import com.sun.tools.javac.tree.DCTree.DCReference;
@@ -336,12 +337,12 @@
                     DCTree text = inlineText();
                     if (text != null) {
                         nextChar();
-                        return m.at(p).UnknownInlineTag(name, List.of(text));
+                        return m.at(p).UnknownInlineTag(name, List.of(text)).setEndPos(bp);
                     }
                 } else if (tp.getKind() == TagParser.Kind.INLINE) {
-                    DCTree tree =  tp.parse(p);
+                    DCEndPosTree<?> tree = (DCEndPosTree<?>) tp.parse(p);
                     if (tree != null) {
-                        return tree;
+                        return tree.setEndPos(bp);
                     }
                 } else {
                     inlineText(); // skip content
@@ -509,7 +510,7 @@
             fac.log.popDiagnosticHandler(deferredDiagnosticHandler);
         }
 
-        return m.at(pos).Reference(sig, qualExpr, member, paramTypes);
+        return m.at(pos).Reference(sig, qualExpr, member, paramTypes).setEndPos(bp);
     }
 
     JCTree parseType(String s) throws ParseException {
@@ -741,7 +742,7 @@
                 }
                 if (ch == '>') {
                     nextChar();
-                    return m.at(p).StartElement(name, attrs, selfClosing);
+                    return m.at(p).StartElement(name, attrs, selfClosing).setEndPos(bp);
                 }
             }
         } else if (ch == '/') {
--- a/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/tree/DCTree.java	Thu May 16 11:47:51 2013 +0100
@@ -36,6 +36,7 @@
 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Position;
 import java.io.IOException;
 import java.io.StringWriter;
 import javax.tools.JavaFileObject;
@@ -82,8 +83,24 @@
         return s.toString();
     }
 
+    public static abstract class DCEndPosTree<T extends DCEndPosTree<T>> extends DCTree {
+
+        private int endPos = Position.NOPOS;
+
+        public int getEndPos(DCDocComment dc) {
+            return dc.comment.getSourcePos(endPos);
+        }
+
+        @SuppressWarnings("unchecked")
+        public T setEndPos(int endPos) {
+            this.endPos = endPos;
+            return (T) this;
+        }
+
+    }
+
     public static class DCDocComment extends DCTree implements DocCommentTree {
-        final Comment comment; // required for the implicit source pos table
+        public final Comment comment; // required for the implicit source pos table
 
         public final List<DCTree> firstSentence;
         public final List<DCTree> body;
@@ -125,7 +142,7 @@
         }
     }
 
-    public static abstract class DCInlineTag extends DCTree implements InlineTagTree {
+    public static abstract class DCInlineTag extends DCEndPosTree<DCInlineTag> implements InlineTagTree {
         public String getTagName() {
             return getKind().tagName;
         }
@@ -345,6 +362,7 @@
         public int getEndPosition(EndPosTable endPosTable) {
             return pos + body.length();
         }
+
     }
 
     public static class DCIdentifier extends DCTree implements IdentifierTree {
@@ -478,7 +496,7 @@
         }
     }
 
-    public static class DCReference extends DCTree implements ReferenceTree {
+    public static class DCReference extends DCEndPosTree<DCReference> implements ReferenceTree {
         public final String signature;
 
         // The following are not directly exposed through ReferenceTree
@@ -663,7 +681,7 @@
         }
     }
 
-    public static class DCStartElement extends DCTree implements StartElementTree {
+    public static class DCStartElement extends DCEndPosTree<DCStartElement> implements StartElementTree {
         public final Name name;
         public final List<DCTree> attrs;
         public final boolean selfClosing;
--- a/langtools/src/share/classes/com/sun/tools/javac/util/Bits.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/Bits.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -27,6 +27,8 @@
 
 import java.util.Arrays;
 
+import static com.sun.tools.javac.util.Bits.BitsOpKind.*;
+
 /** A class for extensible, mutable bit sets.
  *
  *  <p><b>This is NOT part of any supported API.
@@ -36,31 +38,114 @@
  */
 public class Bits {
 
+    public enum BitsOpKind {
+        INIT,
+        CLEAR,
+        INCL_BIT,
+        EXCL_BIT,
+        ASSIGN,
+        AND_SET,
+        OR_SET,
+        DIFF_SET,
+        XOR_SET,
+        INCL_RANGE,
+        EXCL_RANGE,
+    }
+
+    //       ____________      reset    _________
+    //      /  UNKNOWN   \   <-------- / UNINIT  \
+    //      \____________/       |     \_________/
+    //            |              |          |
+    //            |assign        |          | any
+    //            |        ___________      |
+    //            ------> /  NORMAL   \ <----
+    //                    \___________/     |
+    //                            |         |
+    //                            |         |
+    //                            -----------
+    //                               any
+    private enum BitsState {
+        /*  A Bits instance is in UNKNOWN state if it has been explicitly reset.
+         *  It is possible to get to this state from any other by calling the
+         *  reset method. An instance in the UNKNOWN state can pass to the
+         *  NORMAL state after being assigned another Bits instance.
+         */
+        UNKNOWN,
+        /*  A Bits instance is in UNINIT when it is created with the default
+         *  constructor but it isn't explicitly reset. The main objective of this
+         *  internal state is to save some memory.
+         */
+        UNINIT,
+        /*  The normal state is reached after creating a Bits instance from an
+         *  existing one or after applying any operation to an instance on UNINIT
+         *  or NORMAL state. From this state a bits instance can pass to the
+         *  UNKNOWN state by calling the reset method.
+         */
+        NORMAL;
+
+        static BitsState getState(int[] someBits, boolean reset) {
+            if (reset) {
+                return UNKNOWN;
+            } else {
+                if (someBits != unassignedBits) {
+                    return NORMAL;
+                } else {
+                    return UNINIT;
+                }
+            }
+        }
+
+    }
 
     private final static int wordlen = 32;
     private final static int wordshift = 5;
     private final static int wordmask = wordlen - 1;
 
-    private int[] bits;
+    public int[] bits = null;
+    // This field will store last version of bits after every change.
+    public int[] oldBits = null;
+
+    public BitsOpKind lastOperation = null;
+
+    private static final int[] unassignedBits = new int[0];
+
+    private BitsState currentState;
 
     /** Construct an initially empty set.
      */
     public Bits() {
-        this(new int[1]);
+        this(false);
+    }
+
+    public Bits(Bits someBits) {
+        this(someBits.dup().bits, BitsState.getState(someBits.bits, false));
+    }
+
+    public Bits(boolean reset) {
+        this(unassignedBits, BitsState.getState(unassignedBits, reset));
     }
 
     /** Construct a set consisting initially of given bit vector.
      */
-    public Bits(int[] bits) {
+    private Bits(int[] bits, BitsState initState) {
         this.bits = bits;
+        this.currentState = initState;
+        switch (initState) {
+            case UNKNOWN:
+                reset(); //this will also set current state;
+                break;
+            case NORMAL:
+                Assert.check(bits != unassignedBits);
+                lastOperation = INIT;
+                break;
+        }
     }
 
-    /** Construct a set consisting initially of given range.
+    /** This method will be called after any operation that causes a change to
+     *  the bits. Subclasses can thus override it in order to extract information
+     *  from the changes produced to the bits by the given operation.
      */
-    public Bits(int start, int limit) {
-        this();
-        inclRange(start, limit);
-    }
+    public void changed() {}
 
     private void sizeTo(int len) {
         if (bits.length < len) {
@@ -71,57 +156,110 @@
     /** This set = {}.
      */
     public void clear() {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = CLEAR;
         for (int i = 0; i < bits.length; i++) bits[i] = 0;
+        changed();
+        currentState = BitsState.NORMAL;
+    }
+
+    public void reset() {
+        bits = null;
+        oldBits = null;
+        currentState = BitsState.UNKNOWN;
+    }
+
+    public boolean isReset() {
+        return currentState == BitsState.UNKNOWN;
+    }
+
+    public Bits assign(Bits someBits) {
+        lastOperation = ASSIGN;
+        oldBits = bits;
+        bits = someBits.dup().bits;
+        changed();
+        currentState = BitsState.NORMAL;
+        return this;
     }
 
     /** Return a copy of this set.
      */
-    public Bits dup() {
-        int[] newbits = new int[bits.length];
-        System.arraycopy(bits, 0, newbits, 0, bits.length);
-        return new Bits(newbits);
+    private Bits dup() {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        Bits tmp = new Bits();
+        if (currentState != BitsState.NORMAL) {
+            tmp.bits = bits;
+        } else {
+            tmp.bits = new int[bits.length];
+            System.arraycopy(bits, 0, tmp.bits, 0, bits.length);
+        }
+        currentState = BitsState.NORMAL;
+        return tmp;
     }
 
     /** Include x in this set.
      */
     public void incl(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         Assert.check(x >= 0);
+        oldBits = bits;
+        lastOperation = INCL_BIT;
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] |
             (1 << (x & wordmask));
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
 
     /** Include [start..limit) in this set.
      */
     public void inclRange(int start, int limit) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = INCL_RANGE;
         sizeTo((limit >>> wordshift) + 1);
-        for (int x = start; x < limit; x++)
+        for (int x = start; x < limit; x++) {
             bits[x >>> wordshift] = bits[x >>> wordshift] |
                 (1 << (x & wordmask));
+        }
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Exclude [start...end] from this set.
      */
     public void excludeFrom(int start) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = EXCL_RANGE;
         Bits temp = new Bits();
         temp.sizeTo(bits.length);
         temp.inclRange(0, start);
-        andSet(temp);
+        internalAndSet(temp);
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Exclude x from this set.
      */
     public void excl(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         Assert.check(x >= 0);
+        oldBits = bits;
+        lastOperation = EXCL_BIT;
         sizeTo((x >>> wordshift) + 1);
         bits[x >>> wordshift] = bits[x >>> wordshift] &
             ~(1 << (x & wordmask));
+        changed();
+        currentState = BitsState.NORMAL;
     }
 
     /** Is x an element of this set?
      */
     public boolean isMember(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         return
             0 <= x && x < (bits.length << wordshift) &&
             (bits[x >>> wordshift] & (1 << (x & wordmask))) != 0;
@@ -130,38 +268,66 @@
     /** {@literal this set = this set & xs}.
      */
     public Bits andSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = AND_SET;
+        internalAndSet(xs);
+        changed();
+        currentState = BitsState.NORMAL;
+        return this;
+    }
+
+    private void internalAndSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] & xs.bits[i];
-        return this;
+        }
     }
 
     /** this set = this set | xs.
      */
     public Bits orSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = OR_SET;
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] | xs.bits[i];
+        }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
     /** this set = this set \ xs.
      */
     public Bits diffSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = DIFF_SET;
         for (int i = 0; i < bits.length; i++) {
             if (i < xs.bits.length) {
                 bits[i] = bits[i] & ~xs.bits[i];
             }
         }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
     /** this set = this set ^ xs.
      */
     public Bits xorSet(Bits xs) {
+        Assert.check(currentState != BitsState.UNKNOWN);
+        oldBits = bits;
+        lastOperation = XOR_SET;
         sizeTo(xs.bits.length);
-        for (int i = 0; i < xs.bits.length; i++)
+        for (int i = 0; i < xs.bits.length; i++) {
             bits[i] = bits[i] ^ xs.bits[i];
+        }
+        changed();
+        currentState = BitsState.NORMAL;
         return this;
     }
 
@@ -187,6 +353,7 @@
      *  }</pre>
      */
     public int nextBit(int x) {
+        Assert.check(currentState != BitsState.UNKNOWN);
         int windex = x >>> wordshift;
         if (windex >= bits.length) return -1;
         int word = bits[windex] & ~((1 << (x & wordmask))-1);
@@ -202,17 +369,20 @@
     /** a string representation of this set.
      */
     public String toString() {
-        char[] digits = new char[bits.length * wordlen];
-        for (int i = 0; i < bits.length * wordlen; i++)
-            digits[i] = isMember(i) ? '1' : '0';
-        return new String(digits);
+        if (bits.length > 0) {
+            char[] digits = new char[bits.length * wordlen];
+            for (int i = 0; i < bits.length * wordlen; i++)
+                digits[i] = isMember(i) ? '1' : '0';
+            return new String(digits);
+        } else {
+            return "[]";
+        }
     }
 
     /** Test Bits.nextBit(int). */
     public static void main(String[] args) {
         java.util.Random r = new java.util.Random();
         Bits bits = new Bits();
-        int dupCount = 0;
         for (int i=0; i<125; i++) {
             int k;
             do {
--- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -341,9 +341,14 @@
      * </pre>
      */
     public String name() {
-        return getClassName(tsym, false);
+        if (name == null) {
+            name = getClassName(tsym, false);
+        }
+        return name;
     }
 
+    private String name;
+
     /**
      * Return the qualified class name as a String.
      * <pre>
@@ -354,9 +359,14 @@
      * </pre>
      */
     public String qualifiedName() {
-        return getClassName(tsym, true);
+        if (qualifiedName == null) {
+            qualifiedName = getClassName(tsym, true);
+        }
+        return qualifiedName;
     }
 
+    private String qualifiedName;
+
     /**
      * Return unqualified name of type excluding any dimension information.
      * <p>
@@ -380,9 +390,14 @@
      * Return the simple name of this type.
      */
     public String simpleTypeName() {
-        return tsym.name.toString();
+        if (simpleTypeName == null) {
+            simpleTypeName = tsym.name.toString();
+        }
+        return simpleTypeName;
     }
 
+    private String simpleTypeName;
+
     /**
      * Return the qualified name and any type parameters.
      * Each parameter is a type variable with optional bounds.
--- a/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -252,13 +252,23 @@
     }
 
     public String name() {
-        return sym.name.toString();
+        if (name == null) {
+            name = sym.name.toString();
+        }
+        return name;
     }
 
+    private String name;
+
     public String qualifiedName() {
-        return sym.enclClass().getQualifiedName() + "." + name();
+        if (qualifiedName == null) {
+            qualifiedName = sym.enclClass().getQualifiedName() + "." + name();
+        }
+        return qualifiedName;
     }
 
+    private String qualifiedName;
+
     /**
      * Return the source position of the entity, or null if
      * no position is available.
--- a/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/MethodDocImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -203,13 +203,23 @@
 
 
     public String name() {
-        return sym.name.toString();
+        if (name == null) {
+            name = sym.name.toString();
+        }
+        return name;
     }
 
+    private String name;
+
     public String qualifiedName() {
-        return sym.enclClass().getQualifiedName() + "." + sym.name;
+        if (qualifiedName == null) {
+            qualifiedName =  sym.enclClass().getQualifiedName() + "." + sym.name;
+        }
+        return qualifiedName;
     }
 
+    private String qualifiedName;
+
     /**
      * Returns a string representation of this method.  Includes the
      * qualified signature, the qualified method name, and any type
--- a/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -334,12 +334,17 @@
      * Get package name.
      */
     public String qualifiedName() {
-        Name fullname = sym.getQualifiedName();
-        // Some bogus tests depend on the interned "" being returned.
-        // See 6457276.
-        return fullname.isEmpty() ? "" : fullname.toString();
+        if (qualifiedName == null) {
+            Name fullname = sym.getQualifiedName();
+            // Some bogus tests depend on the interned "" being returned.
+            // See 6457276.
+            qualifiedName = fullname.isEmpty() ? "" : fullname.toString();
+        }
+        return qualifiedName;
     }
 
+    private String qualifiedName;
+
     /**
      * set doc path for an unzipped directory
      */
--- a/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Wed May 08 11:22:25 2013 +0100
+++ b/langtools/test/tools/javac/api/TestJavacTaskScanner.java	Thu May 16 11:47:51 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,7 +93,7 @@
         System.out.println("#allMembers: " + numAllMembers);
 
         check(numTokens, "#Tokens", 1222);
-        check(numParseTypeElements, "#parseTypeElements", 136);
+        check(numParseTypeElements, "#parseTypeElements", 158);
         check(numAllMembers, "#allMembers", 52);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/defaultMethods/CheckACC_STRICTFlagOnDefaultMethodTest.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8012723
+ * @summary strictfp interface misses strictfp modifer on default method
+ * @run main CheckACC_STRICTFlagOnDefaultMethodTest
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.io.File;
+import java.io.IOException;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.Method;
+
+import static com.sun.tools.classfile.AccessFlags.ACC_STRICT;
+
+public class CheckACC_STRICTFlagOnDefaultMethodTest {
+    private static final String AssertionErrorMessage =
+        "All methods should have the ACC_STRICT access flag " +
+        "please check output";
+    private static final String offendingMethodErrorMessage =
+        "Method %s of class %s doesn't have the ACC_STRICT access flag";
+
+    private List<String> errors = new ArrayList<>();
+
+    public static void main(String[] args)
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        new CheckACC_STRICTFlagOnDefaultMethodTest().run();
+    }
+
+    private void run()
+            throws IOException, ConstantPoolException, InvalidDescriptor {
+        String testClasses = System.getProperty("test.classes");
+        check(testClasses,
+                "CheckACC_STRICTFlagOnDefaultMethodTest$StrictfpInterface.class");
+        if (errors.size() > 0) {
+            for (String error: errors) {
+                System.err.println(error);
+            }
+            throw new AssertionError(AssertionErrorMessage);
+        }
+    }
+
+    void check(String dir, String... fileNames)
+        throws
+            IOException,
+            ConstantPoolException,
+            Descriptor.InvalidDescriptor {
+        for (String fileName : fileNames) {
+            ClassFile classFileToCheck = ClassFile.read(new File(dir, fileName));
+
+            for (Method method : classFileToCheck.methods) {
+                if ((method.access_flags.flags & ACC_STRICT) == 0) {
+                    errors.add(String.format(offendingMethodErrorMessage,
+                            method.getName(classFileToCheck.constant_pool),
+                            classFileToCheck.getName()));
+                }
+            }
+        }
+    }
+
+    strictfp interface StrictfpInterface {
+        default void default_interface_method() {}
+        static void static_interface_method() {}
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/doctree/positions/TestPosition.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8008174
+ * @summary proper source positions for doc comments
+ * @build TestPosition
+ * @compile/ref=TestPosition.out -processor TestPosition -proc:only TestPositionSource.java
+ */
+
+import com.sun.source.doctree.DocCommentTree;
+import com.sun.source.doctree.DocTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.util.DocSourcePositions;
+import com.sun.source.util.DocTreeScanner;
+import com.sun.source.util.DocTrees;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import java.io.IOException;
+import java.util.Set;
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+
+@SupportedAnnotationTypes("*")
+public class TestPosition extends AbstractProcessor {
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        TypeElement source = processingEnv.getElementUtils().getTypeElement("TestPositionSource");
+
+        if (source == null) throw new IllegalStateException();
+
+        if (!roundEnv.getRootElements().contains(source)) return false;
+
+        final DocTrees trees = DocTrees.instance(processingEnv);
+        final TreePath testElement = trees.getPath(source);
+
+        if (testElement == null) throw new IllegalStateException();
+
+        String code;
+
+        try {
+            code = testElement.getCompilationUnit().getSourceFile().getCharContent(false).toString();
+        } catch ( IOException ex) {
+            throw new IllegalStateException(ex);
+        }
+
+        new TreePathScanner<Void, Void>() {
+            @Override public Void visitMethod(MethodTree node, Void p) {
+                final DocCommentTree docCommentTree = trees.getDocCommentTree(getCurrentPath());
+
+                if (docCommentTree != null) {
+                    System.out.println(node.getName() + ":");
+                    new DocTreeScanner<Void, Void>() {
+                        @Override public Void scan(DocTree node, Void p) {
+                            if (node != null) {
+                                DocSourcePositions sp = (DocSourcePositions) trees.getSourcePositions(); //XXX: the cast???
+                                int start = (int) sp.getStartPosition(testElement.getCompilationUnit(), docCommentTree, node);
+                                int end   = (int) sp.getEndPosition(testElement.getCompilationUnit(), docCommentTree, node);
+                                String snippet = code.substring(start, end).replace(" \n", "!trailing-whitespace!\n");
+
+                                if (snippet.endsWith(" ")) {
+                                    snippet = snippet.substring(0, snippet.length() - 1) + "!trailing-whitespace!";
+                                }
+                                System.out.println(node.getKind().name() + ":" + snippet);
+                            }
+                            return super.scan(node, p);
+                        }
+                    }.scan(docCommentTree, null);
+                }
+
+                return super.visitMethod(node, p);
+            }
+        }.scan(testElement, null);
+
+        return false;
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/doctree/positions/TestPosition.out	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,99 @@
+valid:
+DOC_COMMENT:First sentence.
+     *
+     * <p>Description with {@link java.io.InputStream link}
+     *
+     * @param first description
+     * @param second description
+     * @return whatever
+     * @throws IllegalStateException why?
+     * @since 1.15
+     * @see java.util.List
+TEXT:First sentence.
+START_ELEMENT:<p>
+TEXT:Description with!trailing-whitespace!
+LINK:{@link java.io.InputStream link}
+REFERENCE:java.io.InputStream
+TEXT:link
+PARAM:@param first description
+IDENTIFIER:first
+TEXT:description
+PARAM:@param second description
+IDENTIFIER:second
+TEXT:description
+RETURN:@return whatever
+TEXT:whatever
+THROWS:@throws IllegalStateException why?
+REFERENCE:IllegalStateException
+TEXT:why?
+SINCE:@since 1.15
+TEXT:1.15
+SEE:@see java.util.List
+REFERENCE:java.util.List
+erroneous:
+DOC_COMMENT:First sentence.
+     *
+     * <p>Description with {@link}, {@link java.util.List}, {@link
+     *
+     * @param
+     * @param second
+     * @return
+     * @throws
+     * @throws IllegalStateException
+     * @since
+     * @see
+TEXT:First sentence.
+START_ELEMENT:<p>
+TEXT:Description with!trailing-whitespace!
+LINK:{@link}
+TEXT:,!trailing-whitespace!
+LINK:{@link java.util.List}
+REFERENCE:java.util.List
+TEXT:,!trailing-whitespace!
+ERRONEOUS:{@link
+ERRONEOUS:@param
+PARAM:@param second
+IDENTIFIER:second
+RETURN:@return
+ERRONEOUS:@throws
+THROWS:@throws IllegalStateException
+REFERENCE:IllegalStateException
+SINCE:@since
+ERRONEOUS:@see
+withWhiteSpaces:
+DOC_COMMENT:First sentence.
+     *
+     * <p>Description with {@link    }, {@link java.util.List#add(   int   )},
+     * {@link java.util.List#add(   int   ) some   text   with   whitespaces}, {@link
+     *
+     * @param     first
+     * @param     second   some   text   with trailing whitespace
+     * @return      some   return
+     * @throws      java.lang.IllegalStateException
+     * @throws   java.lang.IllegalStateException some     text
+TEXT:First sentence.
+START_ELEMENT:<p>
+TEXT:Description with!trailing-whitespace!
+LINK:{@link    }
+TEXT:,!trailing-whitespace!
+LINK:{@link java.util.List#add(   int   )}
+REFERENCE:java.util.List#add(   int   )
+TEXT:,
+     *!trailing-whitespace!
+LINK:{@link java.util.List#add(   int   ) some   text   with   whitespaces}
+REFERENCE:java.util.List#add(   int   )
+TEXT:some   text   with   whitespaces
+TEXT:,!trailing-whitespace!
+ERRONEOUS:{@link
+PARAM:@param     first
+IDENTIFIER:first
+PARAM:@param     second   some   text   with trailing whitespace
+IDENTIFIER:second
+TEXT:some   text   with trailing whitespace
+RETURN:@return      some   return
+TEXT:some   return
+THROWS:@throws      java.lang.IllegalStateException
+REFERENCE:java.lang.IllegalStateException
+THROWS:@throws   java.lang.IllegalStateException some     text
+REFERENCE:java.lang.IllegalStateException
+TEXT:some     text
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/doctree/positions/TestPositionSource.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+public class TestPositionSource {
+
+    /**First sentence.
+     *
+     * <p>Description with {@link java.io.InputStream link}
+     *
+     * @param first description
+     * @param second description
+     * @return whatever
+     * @throws IllegalStateException why?
+     * @since 1.15
+     * @see java.util.List
+     */
+    public boolean valid(int first, int second) throws IllegalStateException {
+        return true;
+    }
+
+    /**First sentence.
+     *
+     * <p>Description with {@link}, {@link java.util.List}, {@link
+     *
+     * @param
+     * @param second
+     * @return
+     * @throws
+     * @throws IllegalStateException
+     * @since
+     * @see
+     */
+    public boolean erroneous(int first, int second) throws IllegalStateException {
+        return true;
+    }
+
+    /**First sentence.
+     *
+     * <p>Description with {@link    }, {@link java.util.List#add(   int   )},
+     * {@link java.util.List#add(   int   ) some   text   with   whitespaces}, {@link
+     *
+     * @param     first
+     * @param     second   some   text   with trailing whitespace
+     * @return      some   return
+     * @throws      java.lang.IllegalStateException
+     * @throws   java.lang.IllegalStateException some     text
+     */
+    public boolean withWhiteSpaces(int first, int second) throws IllegalStateException {
+        return true;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/methodReferenceExecution/MethodReferenceTestNewInnerImplicitArgs.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8011591
+ * @summary BootstrapMethodError when capturing constructor ref to local classes
+ * @run testng MethodReferenceTestNewInnerImplicitArgs
+ */
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * Test the case that a constructor has implicit parameters added to
+ * access local variables and that this constructor is used in a
+ * method reference.
+ * @author Robert Field
+ */
+
+@Test
+public class MethodReferenceTestNewInnerImplicitArgs {
+
+
+    static class S {
+        String b;
+        S(String s, String s2) { b = s + s2; }
+    }
+
+    interface I {
+        S m();
+    }
+
+    interface I2 {
+        S m(int i, int j);
+    }
+
+    public static void testConstructorReferenceImplicitParameters() {
+        String title = "Hey";
+        String a2 = "!!!";
+        class MS extends S {
+            MS() {
+                super(title, a2);
+            }
+        }
+
+        I result = MS::new;
+        assertEquals(result.m().b, "Hey!!!");
+
+        class MS2 extends S {
+            MS2(int x, int y) {
+                super(title+x, a2+y);
+            }
+        }
+
+        I2 result2 = MS2::new;
+        assertEquals(result2.m(8, 4).b, "Hey8!!!4");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/processing/model/element/TestTypeParameterAnnotations.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8011027
+ * @library /tools/javac/lib
+ * @build JavacTestingAbstractProcessor TestTypeParameterAnnotations
+ * @compile -processor TestTypeParameterAnnotations -proc:only TestTypeParameterAnnotations.java
+ */
+
+import java.util.*;
+import java.lang.annotation.*;
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.lang.model.util.*;
+import javax.tools.*;
+
+public class TestTypeParameterAnnotations<@Foo @Bar @Baz T> extends JavacTestingAbstractProcessor {
+    int round = 0;
+
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (++round == 1) {
+            int found = (new Scanner()).scan(roundEnv.getRootElements(), null);
+            if (found == expect) {
+                ; //nop
+            } else {
+                error("unexpected number of results: expected " + expect
+                        + ", found " + found);
+            }
+
+        }
+        return true;
+    }
+
+    class Scanner extends JavacTestingAbstractProcessor.ElementScanner<Integer,Void> {
+        @Override
+        public Integer visitExecutable(ExecutableElement e, Void p) {
+            super.visitExecutable(e, p);
+            found += check(e, e.getTypeParameters());
+            return found;
+        }
+
+        @Override
+        public Integer visitType(TypeElement e, Void p) {
+            super.visitType(e, p);
+            found += check(e, e.getTypeParameters());
+            return found;
+        }
+
+        int found;
+    }
+
+    int check(Element e, List<? extends TypeParameterElement> typarams) {
+        if (typarams.isEmpty())
+            return 0;
+        if (typarams.size() != 1)
+            return 0;
+
+        for (TypeParameterElement tpe: typarams) {
+            boolean b1 = checkAnnotationMirrors(tpe, tpe.getAnnotationMirrors());
+            boolean b2 = checkAnnotationMirrors(tpe, elements.getAllAnnotationMirrors(tpe));
+            boolean b3 = checkGetAnnotation(tpe);
+            boolean b4 = checkGetAnnotations(tpe);
+            return b1 && b2 && b3 && b4 ? 1 : 0;
+        }
+        return 0;
+    }
+
+    boolean checkAnnotationMirrors(TypeParameterElement tpe, List<? extends AnnotationMirror> l) {
+        if (l.size() != 3) {
+            error("To few annotations, got " + l.size() +
+                    ", should be 3", tpe);
+            return false;
+        }
+
+        AnnotationMirror m = l.get(0);
+        if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Foo"))) {
+            error("Wrong type of annotation, was expecting @Foo", m.getAnnotationType().asElement());
+            return false;
+        }
+        m = l.get(1);
+        if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Bar"))) {
+            error("Wrong type of annotation, was expecting @Bar", m.getAnnotationType().asElement());
+            return false;
+        }
+        m = l.get(2);
+        if (!m.getAnnotationType().asElement().equals(elements.getTypeElement("Baz"))) {
+            error("Wrong type of annotation, was expecting @Baz", m.getAnnotationType().asElement());
+            return false;
+        }
+        return true;
+    }
+
+    boolean checkGetAnnotation(TypeParameterElement tpe) {
+        Foo f = tpe.getAnnotation(Foo.class);
+        if (f == null)
+            error("Expecting @Foo to be present in getAnnotation()", tpe);
+
+        Bar b = tpe.getAnnotation(Bar.class);
+        if (b == null)
+            error("Expecting @Bar to be present in getAnnotation()", tpe);
+
+        Baz z = tpe.getAnnotation(Baz.class);
+        if (z == null)
+            error("Expecting @Baz to be present in getAnnotation()", tpe);
+
+        return f != null &&
+            b != null &&
+            z != null;
+    }
+
+    boolean checkGetAnnotations(TypeParameterElement tpe) {
+        Foo[] f = tpe.getAnnotationsByType(Foo.class);
+        if (f.length != 1) {
+            error("Expecting 1 @Foo to be present in getAnnotationsByType()", tpe);
+            return false;
+        }
+
+        Bar[] b = tpe.getAnnotationsByType(Bar.class);
+        if (b.length != 1) {
+            error("Expecting 1 @Bar to be present in getAnnotationsByType()", tpe);
+            return false;
+        }
+
+        Baz[] z = tpe.getAnnotationsByType(Baz.class);
+        if (z.length != 1) {
+            error("Expecting 1 @Baz to be present in getAnnotationsByType()", tpe);
+            return false;
+        }
+
+        return true;
+    }
+
+    void note(String msg) {
+        messager.printMessage(Diagnostic.Kind.NOTE, msg);
+    }
+
+    void note(String msg, Element e) {
+        messager.printMessage(Diagnostic.Kind.NOTE, msg, e);
+    }
+
+    void error(String msg, Element e) {
+        messager.printMessage(Diagnostic.Kind.ERROR, msg, e);
+    }
+
+    void error(String msg) {
+        messager.printMessage(Diagnostic.Kind.ERROR, msg);
+    }
+
+    // additional generic elements to test
+    <@Foo @Bar @Baz X> X m(X x) { return x; }
+
+    interface Intf<@Foo @Bar @Baz X> { X m() ; }
+
+    class Class<@Foo @Bar @Baz X> {
+        <@Foo @Bar @Baz Y> Class() { }
+    }
+
+    final int expect = 5;  // top level class, plus preceding examples
+}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Foo {}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Bar {}
+
+@Target(ElementType.TYPE_PARAMETER)
+@interface Baz {}
--- a/nashorn/.hgtags	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/.hgtags	Thu May 16 11:47:51 2013 +0100
@@ -197,3 +197,5 @@
 e0378f0a50dafdcfb7b04f6401d320f89884baa1 jdk8-b85
 002ad9d6735f36d1204e133324c73058c8abb1b0 jdk8-b86
 774aeaa89bc15f4365e3c2fc36f6a3a0da70ba28 jdk8-b87
+40c107d1ae6f81a62e35dfe618b827897405e9b2 jdk8-b88
+45ce27fbe2720d80070095c0db7344ec41e2833d jdk8-b89
--- a/nashorn/bin/verbose_octane.sh	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/bin/verbose_octane.sh	Thu May 16 11:47:51 2013 +0100
@@ -26,7 +26,7 @@
     ITERS=7
 fi
 NASHORN_JAR=dist/nashorn.jar
-JVM_FLAGS="-XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}"
+JVM_FLAGS="-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}"
 JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}"
 OCTANE_ARGS="--verbose --iterations ${ITERS}"
 
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java	Thu May 16 11:47:51 2013 +0100
@@ -38,7 +38,6 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
@@ -47,6 +46,8 @@
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC;
 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
@@ -238,7 +239,7 @@
             mi.loadThis();
             mi.invokeStatic(PROTOTYPEOBJECT_TYPE, PROTOTYPEOBJECT_SETCONSTRUCTOR,
                     PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC);
-            mi.putField(SCRIPTFUNCTION_TYPE, PROTOTYPE, OBJECT_DESC);
+            mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETPROTOTYPE, SCRIPTFUNCTION_SETPROTOTYPE_DESC);
         }
     }
 
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java	Thu May 16 11:47:51 2013 +0100
@@ -55,7 +55,6 @@
     static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
     static final Type TYPE_SCRIPTOBJECT       = Type.getType(ScriptObject.class);
 
-    static final String PROTOTYPE = "prototype";
     static final String PROTOTYPE_SUFFIX = "$Prototype";
     static final String CONSTRUCTOR_SUFFIX = "$Constructor";
     // This field name is known to Nashorn runtime (Context).
@@ -88,6 +87,8 @@
         Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
     static final String SCRIPTFUNCTION_SETARITY = "setArity";
     static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
+    static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
+    static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
     static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName();
     static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor";
     static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT);
--- a/nashorn/make/build-nasgen.xml	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/make/build-nasgen.xml	Thu May 16 11:47:51 2013 +0100
@@ -37,6 +37,7 @@
                 <pathelement location="${basedir}/buildtools/nasgen/dist/nasgen.jar"/>
                 <pathelement path="${basedir}/build/classes"/>
             </classpath>
+            <jvmarg value="-Djava.ext.dirs="/>
             <arg value="${basedir}/build/classes"/>
             <arg value="jdk.nashorn.internal.objects"/>
             <arg value="${basedir}/build/classes"/>
--- a/nashorn/make/project.properties	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/make/project.properties	Thu May 16 11:47:51 2013 +0100
@@ -214,7 +214,7 @@
 
 #  -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods
 # add '-Dtest.js.outofprocess' to run each test in a new sub-process
-run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
+run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M  
 run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
 
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Thu May 16 11:47:51 2013 +0100
@@ -106,7 +106,11 @@
 
     @Override
     MethodHandle editMethodHandle(MethodHandle mh) {
-        MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, Object.class);
+        return dropReceiver(mh, Object.class);
+    }
+
+    static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
+        MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
         // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
         if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
             final MethodType type = mh.type();
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java	Thu May 16 11:47:51 2013 +0100
@@ -144,7 +144,7 @@
         }
 
         private static MethodHandle drop(MethodHandle mh) {
-            return MethodHandles.dropArguments(mh, 0, StaticClass.class);
+            return StaticClassIntrospector.dropReceiver(mh, StaticClass.class);
         }
 
         @Override
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu May 16 11:47:51 2013 +0100
@@ -397,10 +397,7 @@
             }
 
             setContextVariables(ctxt);
-            final Object val = ctxt.getAttribute(ScriptEngine.FILENAME);
-            final String fileName = (val != null) ? val.toString() : "<eval>";
-            Object res = ScriptRuntime.apply(script, ctxtGlobal);
-            return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal));
+            return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
         } catch (final Exception e) {
             throwAsScriptException(e);
             throw new AssertionError("should not reach here");
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Thu May 16 11:47:51 2013 +0100
@@ -25,14 +25,16 @@
 
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX;
+import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
+import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF;
 import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
 import static jdk.nashorn.internal.ir.Symbol.IS_LET;
@@ -42,18 +44,18 @@
 import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
 import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Deque;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.ListIterator;
 import java.util.Set;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.CallNode;
-import jdk.nashorn.internal.ir.CallNode.EvalArgs;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -62,6 +64,7 @@
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LexicalContextNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.Node;
@@ -76,6 +79,7 @@
 import jdk.nashorn.internal.ir.TryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
+import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
@@ -105,21 +109,22 @@
  */
 
 final class Attr extends NodeOperatorVisitor {
+
     /**
      * Local definitions in current block (to discriminate from function
      * declarations always defined in the function scope. This is for
      * "can be undefined" analysis.
      */
-    private Set<String> localDefs;
+    private final Deque<Set<String>> localDefs;
 
     /**
      * Local definitions in current block to guard against cases like
      * NASHORN-467 when things can be undefined as they are used before
      * their local var definition. *sigh* JavaScript...
      */
-    private Set<String> localUses;
+    private final Deque<Set<String>> localUses;
 
-    private final LexicalContext lexicalContext = new LexicalContext();
+    private final Deque<Type> returnTypes;
 
     private static final DebugLogger LOG   = new DebugLogger("attr");
     private static final boolean     DEBUG = LOG.isEnabled();
@@ -128,10 +133,13 @@
      * Constructor.
      */
     Attr() {
+        localDefs = new ArrayDeque<>();
+        localUses = new ArrayDeque<>();
+        returnTypes = new ArrayDeque<>();
     }
 
     @Override
-    protected Node enterDefault(final Node node) {
+    protected boolean enterDefault(final Node node) {
         return start(node);
     }
 
@@ -142,217 +150,47 @@
 
     @Override
     public Node leaveAccessNode(final AccessNode accessNode) {
-        newTemporary(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
+        ensureSymbol(Type.OBJECT, accessNode);  //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
         end(accessNode);
         return accessNode;
     }
 
-    @Override
-    public Node enterBlock(final Block block) {
-        lexicalContext.push(block);
-        start(block);
-
-        final Set<String> savedLocalDefs = localDefs;
-        final Set<String> savedLocalUses = localUses;
-
-        block.setFrame(getCurrentFunctionNode().pushFrame());
-
-        try {
-            // a block starts out by copying the local defs and local uses
-            // from the outer level. But we need the copies, as when we
-            // leave the block the def and use sets given upon entry must
-            // be restored
-            localDefs = new HashSet<>(savedLocalDefs);
-            localUses = new HashSet<>(savedLocalUses);
-
-            block.visitStatements(this);
-        } finally {
-            localDefs = savedLocalDefs;
-            localUses = savedLocalUses;
-
-            getCurrentFunctionNode().popFrame();
-        }
-
-        end(block);
-
-        lexicalContext.pop(block);
-        return null;
-    }
-
-    @Override
-    public Node enterCallNode(final CallNode callNode) {
-        start(callNode);
-
-        callNode.getFunction().accept(this);
-
-        final List<Node> acceptedArgs = new ArrayList<>(callNode.getArgs().size());
-        for (final Node arg : callNode.getArgs()) {
-            LOG.info("Doing call arg " + arg);
-            acceptedArgs.add(arg.accept(this));
-        }
-        callNode.setArgs(acceptedArgs);
+    private void enterFunctionBody() {
 
-        final EvalArgs evalArgs = callNode.getEvalArgs();
-        if (evalArgs != null) {
-            evalArgs.setCode(evalArgs.getCode().accept(this));
-
-            final IdentNode thisNode = new IdentNode(getCurrentFunctionNode().getThisNode());
-            assert thisNode.getSymbol() != null; //should copy attributed symbol and that's it
-            evalArgs.setThis(thisNode);
-        }
-
-        newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later
-
-        end(callNode);
-
-        return null;
-    }
-
-    @Override
-    public Node enterCatchNode(final CatchNode catchNode) {
-        final IdentNode exception = catchNode.getException();
-        final Block     block     = getCurrentBlock();
-
-        start(catchNode);
-
-        // define block-local exception variable
-        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
-        newType(def, Type.OBJECT);
-        addLocalDef(exception.getName());
-
-        return catchNode;
-    }
-
-    /**
-     * Declare the definition of a new symbol.
-     *
-     * @param name         Name of symbol.
-     * @param symbolFlags  Symbol flags.
-     * @param node         Defining Node.
-     *
-     * @return Symbol for given name or null for redefinition.
-     */
-    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
-        int    flags  = symbolFlags;
-        Symbol symbol = findSymbol(block, name); // Locate symbol.
-
-        if ((flags & KINDMASK) == IS_GLOBAL) {
-            flags |= IS_SCOPE;
+        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+        final Block body = getLexicalContext().getCurrentBlock();
+        initCallee(body);
+        initThis(body);
+        if (functionNode.isVarArg()) {
+            initVarArg(body, functionNode.needsArguments());
         }
 
-        final FunctionNode function = lexicalContext.getFunction(block);
-        if (symbol != null) {
-            // Symbol was already defined. Check if it needs to be redefined.
-            if ((flags & KINDMASK) == IS_PARAM) {
-                if (!isLocal(function, symbol)) {
-                    // Not defined in this function. Create a new definition.
-                    symbol = null;
-                } else if (symbol.isParam()) {
-                    // Duplicate parameter. Null return will force an error.
-                    assert false : "duplicate parameter";
-                    return null;
-                }
-            } else if ((flags & KINDMASK) == IS_VAR) {
-                if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
-                    assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block";
-                    // Always create a new definition.
-                    symbol = null;
-                } else {
-                    // Not defined in this function. Create a new definition.
-                    if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
-                        symbol = null;
-                    }
-                }
-            }
-        }
-
-        if (symbol == null) {
-            // If not found, then create a new one.
-            Block symbolBlock;
-
-            // Determine where to create it.
-            if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
-                symbolBlock = block;
-            } else {
-                symbolBlock = function;
-            }
-
-            // Create and add to appropriate block.
-            symbol = new Symbol(name, flags, node, symbolBlock);
-            symbolBlock.putSymbol(name, symbol);
-
-            if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
-                symbolBlock.getFrame().addSymbol(symbol);
-                symbol.setNeedsSlot(true);
-            }
-        } else if (symbol.less(flags)) {
-            symbol.setFlags(flags);
-        }
-
-        if (node != null) {
-            node.setSymbol(symbol);
-        }
-
-        return symbol;
-    }
-
-    @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        start(functionNode, false);
-        if (functionNode.isLazy()) {
-            LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT");
-            newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode);
-            functionNode.setReturnType(Type.OBJECT);
-            end(functionNode);
-            return null;
-        }
-
-        lexicalContext.push(functionNode);
-
-        clearLocalDefs();
-        clearLocalUses();
-
-        functionNode.setFrame(functionNode.pushFrame());
-
-        initCallee(functionNode);
-        initThis(functionNode);
-        if (functionNode.isVarArg()) {
-            initVarArg(functionNode);
-        }
-
-        initParameters(functionNode);
-        initScope(functionNode);
-        initReturn(functionNode);
-
-        // Add all nested declared functions as symbols in this function
-        for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) {
-            final IdentNode ident = nestedFunction.getIdent();
-            if (ident != null) {
-                assert nestedFunction.isDeclared();
-                final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction);
-                newType(functionSymbol, Type.typeFor(ScriptFunction.class));
-            }
-        }
+        initParameters(functionNode, body);
+        initScope(body);
+        initReturn(body);
 
         if (functionNode.isProgram()) {
-            initFromPropertyMap(functionNode);
-        }
+            initFromPropertyMap(body);
+        } else if(!functionNode.isDeclared()) {
+            // It's neither declared nor program - it's a function expression then; assign it a self-symbol.
 
-        // Add function name as local symbol
-        if (!functionNode.isDeclared() && !functionNode.isProgram()) {
-            if(functionNode.getSymbol() != null) {
+            if (functionNode.getSymbol() != null) {
                 // a temporary left over from an earlier pass when the function was lazy
                 assert functionNode.getSymbol().isTemp();
                 // remove it
                 functionNode.setSymbol(null);
             }
-            final Symbol selfSymbol;
-            if(functionNode.isAnonymous()) {
-                selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode);
+            final boolean anonymous = functionNode.isAnonymous();
+            final String name = anonymous ? null : functionNode.getIdent().getName();
+            if (anonymous || body.getExistingSymbol(name) != null) {
+                // The function is either anonymous, or another local identifier already trumps its name on entry:
+                // either it has the same name as one of its parameters, or is named "arguments" and also references the
+                // "arguments" identifier in its body.
+                ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode);
             } else {
-                selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode);
+                final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode);
+                assert selfSymbol.isFunctionSelf();
                 newType(selfSymbol, Type.OBJECT);
-                selfSymbol.setNode(functionNode);
             }
         }
 
@@ -373,73 +211,243 @@
          * @see NASHORN-73
          */
 
-        final List<Symbol> declaredSymbols = new ArrayList<>();
         // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
         // in a separate step above) and "var" declarations in for loop initializers.
-        functionNode.accept(new NodeOperatorVisitor() {
+        body.accept(new NodeOperatorVisitor() {
             @Override
-            public Node enterFunctionNode(FunctionNode nestedFn) {
-                // Don't descend into nested functions
-                return nestedFn == functionNode ? nestedFn : null;
+            public boolean enterFunctionNode(final FunctionNode nestedFn) {
+                return false;
             }
+
             @Override
-            public Node enterVarNode(VarNode varNode) {
-                if(varNode.isStatement() && !varNode.isFunctionDeclaration()) {
+            public boolean enterVarNode(final VarNode varNode) {
+
+                // any declared symbols that aren't visited need to be typed as well, hence the list
+
+                if (varNode.isStatement()) {
+
                     final IdentNode ident = varNode.getName();
-                    // any declared symbols that aren't visited need to be typed as well, hence the list
-                    declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident)));
+                    final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident));
+                    functionNode.addDeclaredSymbol(symbol);
+                    if (varNode.isFunctionDeclaration()) {
+                        newType(symbol, FunctionNode.FUNCTION_TYPE);
+                    }
                 }
-                return null;
+                return false;
             }
         });
+    }
 
-        visitFunctionStatements(functionNode);
+    @Override
+    public boolean enterBlock(final Block block) {
+        start(block);
+
+        if (getLexicalContext().isFunctionBody()) {
+            enterFunctionBody();
+        }
+        pushLocalsBlock();
+
+        return true;
+    }
+
+    @Override
+    public Node leaveBlock(final Block block) {
+        popLocals();
+        return end(block);
+    }
+
+    @Override
+    public Node leaveCallNode(final CallNode callNode) {
+        ensureSymbol(callNode.getType(), callNode);
+        return end(callNode);
+    }
+
+    @Override
+    public boolean enterCallNode(final CallNode callNode) {
+        return start(callNode);
+    }
+
+    @Override
+    public boolean enterCatchNode(final CatchNode catchNode) {
+        final IdentNode exception = catchNode.getException();
+        final Block     block     = getLexicalContext().getCurrentBlock();
+
+        start(catchNode);
+
+        // define block-local exception variable
+        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
+        newType(def, Type.OBJECT);
+        addLocalDef(exception.getName());
+
+        return true;
+    }
+
+    /**
+     * Declare the definition of a new symbol.
+     *
+     * @param name         Name of symbol.
+     * @param symbolFlags  Symbol flags.
+     * @param node         Defining Node.
+     *
+     * @return Symbol for given name or null for redefinition.
+     */
+    private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
+        int    flags  = symbolFlags;
+        Symbol symbol = findSymbol(block, name); // Locate symbol.
+
+        if ((flags & KINDMASK) == IS_GLOBAL) {
+            flags |= IS_SCOPE;
+        }
+
+        final FunctionNode function = getLexicalContext().getFunction(block);
+        if (symbol != null) {
+            // Symbol was already defined. Check if it needs to be redefined.
+            if ((flags & KINDMASK) == IS_PARAM) {
+                if (!isLocal(function, symbol)) {
+                    // Not defined in this function. Create a new definition.
+                    symbol = null;
+                } else if (symbol.isParam()) {
+                    // Duplicate parameter. Null return will force an error.
+                    assert false : "duplicate parameter";
+                    return null;
+                }
+            } else if ((flags & KINDMASK) == IS_VAR) {
+                if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
+                    // Always create a new definition.
+                    symbol = null;
+                } else {
+                    // Not defined in this function. Create a new definition.
+                    if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
+                        symbol = null;
+                    }
+                }
+            }
+        }
+
+        if (symbol == null) {
+            // If not found, then create a new one.
+            Block symbolBlock;
+
+            // 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 {
+                symbolBlock = getLexicalContext().getFunctionBody(function);
+            }
+
+            // Create and add to appropriate block.
+            symbol = new Symbol(name, flags);
+            symbolBlock.putSymbol(name, symbol);
+
+            if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
+                symbol.setNeedsSlot(true);
+            }
+        } else if (symbol.less(flags)) {
+            symbol.setFlags(flags);
+        }
+
+        if (node != null) {
+            node.setSymbol(symbol);
+        }
+
+        return symbol;
+    }
+
+    @Override
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        start(functionNode, false);
+
+        if (functionNode.isDeclared()) {
+            final Iterator<Block> blocks = getLexicalContext().getBlocks();
+            if (blocks.hasNext()) {
+                defineSymbol(
+                    blocks.next(),
+                    functionNode.getIdent().getName(),
+                    IS_VAR,
+                    functionNode);
+            } else {
+                // Q: What's an outermost function in a lexical context that is not a program?
+                // A: It's a function being compiled lazily!
+                assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram();
+            }
+        }
+
+        if (functionNode.isLazy()) {
+            LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT");
+            ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode);
+            end(functionNode);
+            return false;
+        }
+
+        returnTypes.push(functionNode.getReturnType());
+        pushLocalsFunction();
+        return true;
+    }
+
+    @Override
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        FunctionNode newFunctionNode = functionNode;
+
+        final LexicalContext lc = getLexicalContext();
 
         //unknown parameters are promoted to object type.
-        finalizeParameters(functionNode);
-        finalizeTypes(functionNode);
-        for (final Symbol symbol : declaredSymbols) {
+        finalizeParameters(newFunctionNode);
+        finalizeTypes(newFunctionNode);
+        for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) {
             if (symbol.getSymbolType().isUnknown()) {
                 symbol.setType(Type.OBJECT);
                 symbol.setCanBeUndefined();
             }
         }
 
-        if (functionNode.getReturnType().isUnknown()) {
-            LOG.info("Unknown return type promoted to object");
-            functionNode.setReturnType(Type.OBJECT);
-        }
+        final Block body = newFunctionNode.getBody();
 
-        if (functionNode.getSelfSymbolInit() != null) {
-            LOG.info("Accepting self symbol init " + functionNode.getSelfSymbolInit() + " for " + functionNode.getName());
-            final Node init = functionNode.getSelfSymbolInit();
-            final List<Node> newStatements = new ArrayList<>();
-            newStatements.add(init);
-            newStatements.addAll(functionNode.getStatements());
-            functionNode.setStatements(newStatements);
-            functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this));
+        if (newFunctionNode.hasLazyChildren()) {
+            //the final body has already been assigned as we have left the function node block body by now
+            objectifySymbols(body);
         }
 
-        if (functionNode.hasLazyChildren()) {
-            objectifySymbols(functionNode);
+        if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) {
+            final IdentNode callee = compilerConstant(CALLEE);
+            final VarNode selfInit =
+                new VarNode(
+                    newFunctionNode.getSource(),
+                    newFunctionNode.getToken(),
+                    newFunctionNode.getFinish(),
+                    newFunctionNode.getIdent(),
+                    callee);
+
+            LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName());
+
+            final List<Node> newStatements = new ArrayList<>();
+            newStatements.add(selfInit);
+            assert callee.getSymbol() != null && callee.getSymbol().hasSlot();
+
+            final IdentNode name       = selfInit.getName();
+            final Symbol    nameSymbol = body.getExistingSymbol(name.getName());
+
+            assert nameSymbol != null;
+
+            name.setSymbol(nameSymbol);
+            selfInit.setSymbol(nameSymbol);
+
+            newStatements.addAll(body.getStatements());
+            newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements));
         }
 
-        functionNode.popFrame();
-
-        functionNode.setState(CompilationState.ATTR);
-
-        end(functionNode, false);
-        lexicalContext.pop(functionNode);
+        if (returnTypes.peek().isUnknown()) {
+            LOG.info("Unknown return type promoted to object");
+            newFunctionNode = newFunctionNode.setReturnType(lc, Type.OBJECT);
+        }
+        final Type returnType = returnTypes.pop();
+        newFunctionNode = newFunctionNode.setReturnType(lc, returnType.isUnknown() ? Type.OBJECT : returnType);
+        newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR);
 
-        return null;
-    }
+        popLocals();
 
-    private void visitFunctionStatements(final FunctionNode functionNode) {
-        final List<Node> newStatements = new ArrayList<>(functionNode.getStatements());
-        for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) {
-            stmts.set(stmts.next().accept(this));
-        }
-        functionNode.setStatements(newStatements);
+        end(newFunctionNode, false);
+
+        return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode));
     }
 
     @Override
@@ -450,7 +458,7 @@
     }
 
     @Override
-    public Node enterIdentNode(final IdentNode identNode) {
+    public boolean enterIdentNode(final IdentNode identNode) {
         final String name = identNode.getName();
 
         start(identNode);
@@ -458,31 +466,28 @@
         if (identNode.isPropertyName()) {
             // assign a pseudo symbol to property name
             final Symbol pseudoSymbol = pseudoSymbol(name);
-            LOG.info("IdentNode is property name -> assigning pseudo symbol " + pseudoSymbol);
+            LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol);
             LOG.unindent();
             identNode.setSymbol(pseudoSymbol);
-            return null;
+            return false;
         }
 
-        final Block  block     = getCurrentBlock();
-        final Symbol oldSymbol = identNode.getSymbol();
+        final LexicalContext lc        = getLexicalContext();
+        final Block          block     = lc.getCurrentBlock();
+        final Symbol         oldSymbol = identNode.getSymbol();
 
         Symbol symbol = findSymbol(block, name);
 
         //If an existing symbol with the name is found, use that otherwise, declare a new one
         if (symbol != null) {
-            LOG.info("Existing symbol = " + symbol);
-            if (isFunctionExpressionSelfReference(symbol)) {
-                final FunctionNode functionNode = (FunctionNode)symbol.getNode();
-                assert functionNode.getCalleeNode() != null;
-
-                final VarNode var = new VarNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode());
-                //newTemporary(Type.OBJECT, var); //ScriptFunction? TODO
-
-                functionNode.setNeedsSelfSymbol(var);
-            }
-
-            if (!identNode.isInitializedHere()) { // NASHORN-448
+            LOG.info("Existing symbol = ", symbol);
+            if (symbol.isFunctionSelf()) {
+                final FunctionNode functionNode = lc.getDefiningFunction(symbol);
+                assert functionNode != null;
+                assert lc.getFunctionBody(functionNode).getExistingSymbol(CALLEE.symbolName()) != null;
+                lc.setFlag(functionNode.getBody(), Block.NEEDS_SELF_SYMBOL);
+                newType(symbol, FunctionNode.FUNCTION_TYPE);
+            } else if (!identNode.isInitializedHere()) { // NASHORN-448
                 // here is a use outside the local def scope
                 if (!isLocalDef(name)) {
                     newType(symbol, Type.OBJECT);
@@ -491,26 +496,18 @@
             }
 
             identNode.setSymbol(symbol);
-            // non-local: we need to put symbol in scope (if it isn't already)
-            if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) {
-                symbol.setIsScope();
-            }
+            // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already)
+            maybeForceScope(symbol);
         } else {
-            LOG.info("No symbol exists. Declare undefined: " + symbol);
-            symbol = useSymbol(block, name, identNode);
+            LOG.info("No symbol exists. Declare undefined: ", symbol);
+            symbol = defineSymbol(block, name, IS_GLOBAL, identNode);
             // we have never seen this before, it can be undefined
             newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
             symbol.setCanBeUndefined();
-            symbol.setIsScope();
+            Symbol.setSymbolIsScope(lc, symbol);
         }
 
-        assert symbol != null;
-        if(symbol.isGlobal()) {
-            setUsesGlobalSymbol();
-        } else if(symbol.isScope()) {
-            final Iterator<Block> blocks = lexicalContext.getBlocks();
-            blocks.next().setUsesScopeSymbol(symbol, blocks);
-        }
+        setBlockScope(name, symbol);
 
         if (symbol != oldSymbol && !identNode.isInitializedHere()) {
             symbol.increaseUseCount();
@@ -519,7 +516,81 @@
 
         end(identNode);
 
-        return null;
+        return false;
+    }
+
+    /**
+     * If the symbol isn't already a scope symbol, and it is either not local to the current function, or it is being
+     * referenced from within a with block, we force it to be a scope symbol.
+     * @param symbol the symbol that might be scoped
+     */
+    private void maybeForceScope(final Symbol symbol) {
+        if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) {
+            Symbol.setSymbolIsScope(getLexicalContext(), symbol);
+        }
+    }
+
+    private boolean symbolNeedsToBeScope(Symbol symbol) {
+        if(symbol.isThis() || symbol.isInternal()) {
+            return false;
+        }
+        boolean previousWasBlock = false;
+        for(final Iterator<LexicalContextNode> it = getLexicalContext().getAllNodes(); it.hasNext();) {
+            final LexicalContextNode node = it.next();
+            if(node instanceof FunctionNode) {
+                // We reached the function boundary without seeing a definition for the symbol - it needs to be in
+                // scope.
+                return true;
+            } else if(node instanceof WithNode) {
+                if(previousWasBlock) {
+                    // We reached a WithNode; the symbol must be scoped. Note that if the WithNode was not immediately
+                    // preceded by a block, this means we're currently processing its expression, not its body,
+                    // therefore it doesn't count.
+                    return true;
+                }
+                previousWasBlock = false;
+            } else if(node instanceof Block) {
+                if(((Block)node).getExistingSymbol(symbol.getName()) == symbol) {
+                    // We reached the block that defines the symbol without reaching either the function boundary, or a
+                    // WithNode. The symbol need not be scoped.
+                    return false;
+                }
+                previousWasBlock = true;
+            } else {
+                previousWasBlock = false;
+            }
+        }
+        throw new AssertionError();
+    }
+
+    private void setBlockScope(final String name, final Symbol symbol) {
+        assert symbol != null;
+        if (symbol.isGlobal()) {
+            setUsesGlobalSymbol();
+            return;
+        }
+
+        if (symbol.isScope()) {
+            final LexicalContext lc = getLexicalContext();
+
+            Block scopeBlock = null;
+            for (final Iterator<LexicalContextNode> contextNodeIter = getLexicalContext().getAllNodes(); contextNodeIter.hasNext(); ) {
+                final LexicalContextNode node = contextNodeIter.next();
+                if (node instanceof Block) {
+                    if (((Block)node).getExistingSymbol(name) != null) {
+                        scopeBlock = (Block)node;
+                        break;
+                    }
+                } else if (node instanceof FunctionNode) {
+                    lc.setFlag(node, FunctionNode.USES_ANCESTOR_SCOPE);
+                }
+            }
+
+            if (scopeBlock != null) {
+                assert getLexicalContext().contains(scopeBlock);
+                lc.setFlag(scopeBlock, Block.NEEDS_SCOPE);
+            }
+        }
     }
 
     /**
@@ -528,35 +599,12 @@
      * @see #needsParentScope()
      */
     private void setUsesGlobalSymbol() {
-        for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) {
-            fns.next().setUsesAncestorScope();
+        for (final Iterator<FunctionNode> fns = getLexicalContext().getFunctions(); fns.hasNext();) {
+            getLexicalContext().setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE);
         }
     }
 
     /**
-     * Declare the use of a symbol in a block.
-     *
-     * @param block block in which the symbol is used
-     * @param name Name of symbol.
-     * @param node Using node
-     *
-     * @return Symbol for given name.
-     */
-    private Symbol useSymbol(final Block block, final String name, final Node node) {
-        Symbol symbol = findSymbol(block, name);
-
-        if (symbol == null) {
-            // If not found, declare as a free var.
-            symbol = defineSymbol(block, name, IS_GLOBAL, node);
-        } else {
-            node.setSymbol(symbol);
-        }
-
-        return symbol;
-    }
-
-
-    /**
      * Search for symbol in the lexical context starting from the given block.
      * @param name Symbol name.
      * @return Found symbol or null if not found.
@@ -564,7 +612,7 @@
     private Symbol findSymbol(final Block block, final String name) {
         // Search up block chain to locate symbol.
 
-        for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) {
+        for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) {
             // Find name.
             final Symbol symbol = blocks.next().getExistingSymbol(name);
             // If found then we are good.
@@ -577,13 +625,13 @@
 
     @Override
     public Node leaveIndexNode(final IndexNode indexNode) {
-        newTemporary(Type.OBJECT, indexNode); //TODO
+        ensureSymbol(Type.OBJECT, indexNode); //TODO
         return indexNode;
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    public Node enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         try {
             start(literalNode);
             assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
@@ -604,26 +652,33 @@
                 assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported";
             }
 
-            getCurrentFunctionNode().newLiteral(literalNode);
+            getLexicalContext().getCurrentFunction().newLiteral(literalNode);
         } finally {
             end(literalNode);
         }
-        return null;
+
+        return false;
+    }
+
+    @Override
+    public boolean enterObjectNode(final ObjectNode objectNode) {
+        return start(objectNode);
     }
 
     @Override
     public Node leaveObjectNode(final ObjectNode objectNode) {
-        newTemporary(Type.OBJECT, objectNode);
-        end(objectNode);
-        return objectNode;
+        ensureSymbol(Type.OBJECT, objectNode);
+        return end(objectNode);
     }
 
+    //TODO is this correct why not leave?
     @Override
-    public Node enterPropertyNode(final PropertyNode propertyNode) {
+    public boolean enterPropertyNode(final PropertyNode propertyNode) {
         // assign a pseudo symbol to property name, see NASHORN-710
+        start(propertyNode);
         propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
         end(propertyNode);
-        return propertyNode;
+        return true;
     }
 
     @Override
@@ -636,8 +691,10 @@
             if (expr.getType().isUnknown() && symbol.isParam()) {
                 symbol.setType(Type.OBJECT);
             }
-            getCurrentFunctionNode().setReturnType(Type.widest(getCurrentFunctionNode().getReturnType(), symbol.getSymbolType()));
-            LOG.info("Returntype is now " + getCurrentFunctionNode().getReturnType());
+
+            final Type returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType());
+            returnTypes.push(returnType);
+            LOG.info("Returntype is now ", returnType);
         }
 
         end(returnNode);
@@ -649,25 +706,29 @@
     public Node leaveSwitchNode(final SwitchNode switchNode) {
         Type type = Type.UNKNOWN;
 
+        final List<CaseNode> newCases = new ArrayList<>();
         for (final CaseNode caseNode : switchNode.getCases()) {
             final Node test = caseNode.getTest();
+
+            CaseNode newCaseNode = caseNode;
             if (test != null) {
                 if (test instanceof LiteralNode) {
                     //go down to integers if we can
                     final LiteralNode<?> lit = (LiteralNode<?>)test;
                     if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
                         if (JSType.isRepresentableAsInt(lit.getNumber())) {
-                            caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
+                            newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
                         }
                     }
                 } else {
                     // the "all integer" case that CodeGenerator optimizes for currently assumes literals only
                     type = Type.OBJECT;
-                    break;
                 }
 
-                type = Type.widest(type, caseNode.getTest().getType());
+                type = Type.widest(type, newCaseNode.getTest().getType());
             }
+
+            newCases.add(newCaseNode);
         }
 
         //only optimize for all integers
@@ -675,11 +736,11 @@
             type = Type.OBJECT;
         }
 
-        switchNode.setTag(newInternal(getCurrentFunctionNode().uniqueName(SWITCH_TAG_PREFIX.tag()), type));
+        switchNode.setTag(newInternal(getLexicalContext().getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type));
 
         end(switchNode);
 
-        return switchNode;
+        return switchNode.setCases(getLexicalContext(), newCases);
     }
 
     @Override
@@ -696,25 +757,25 @@
     }
 
     @Override
-    public Node enterVarNode(final VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         start(varNode);
 
         final IdentNode ident = varNode.getName();
         final String    name  = ident.getName();
 
-        final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident);
+        final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident);
         assert symbol != null;
 
-        LOG.info("VarNode " + varNode + " set symbol " + symbol);
+        LOG.info("VarNode ", varNode, " set symbol ", symbol);
         varNode.setSymbol(symbol);
 
         // NASHORN-467 - use before definition of vars - conservative
-        if (localUses.contains(ident.getName())) {
+        if (isLocalUse(ident.getName())) {
             newType(symbol, Type.OBJECT);
             symbol.setCanBeUndefined();
         }
 
-        return varNode;
+        return true;
     }
 
     @Override
@@ -734,7 +795,7 @@
         addLocalDef(name);
 
         final Symbol  symbol   = varNode.getSymbol();
-        final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56
+        final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56
         if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
             // Forbid integers as local vars for now as we have no way to treat them as undefined
             newType(symbol, init.getType());
@@ -751,14 +812,14 @@
 
     @Override
     public Node leaveADD(final UnaryNode unaryNode) {
-        newTemporary(arithType(), unaryNode);
+        ensureSymbol(arithType(), unaryNode);
         end(unaryNode);
         return unaryNode;
     }
 
     @Override
     public Node leaveBIT_NOT(final UnaryNode unaryNode) {
-        newTemporary(Type.INT, unaryNode);
+        ensureSymbol(Type.INT, unaryNode);
         end(unaryNode);
         return unaryNode;
     }
@@ -766,30 +827,29 @@
     @Override
     public Node leaveDECINC(final UnaryNode unaryNode) {
         // @see assignOffset
-        ensureAssignmentSlots(getCurrentFunctionNode(), unaryNode.rhs());
+        ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs());
         final Type type = arithType();
         newType(unaryNode.rhs().getSymbol(), type);
-        newTemporary(type, unaryNode);
+        ensureSymbol(type, unaryNode);
         end(unaryNode);
         return unaryNode;
     }
 
     @Override
     public Node leaveDELETE(final UnaryNode unaryNode) {
-        final FunctionNode   currentFunctionNode = getCurrentFunctionNode();
-        final boolean        strictMode          = currentFunctionNode.isStrictMode();
+        final FunctionNode   currentFunctionNode = getLexicalContext().getCurrentFunction();
+        final boolean        strictMode          = currentFunctionNode.isStrict();
         final Node           rhs                 = unaryNode.rhs();
         final Node           strictFlagNode      = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
 
         Request request = Request.DELETE;
-        final RuntimeNode runtimeNode;
         final List<Node> args = new ArrayList<>();
 
         if (rhs instanceof IdentNode) {
             // If this is a declared variable or a function parameter, delete always fails (except for globals).
             final String name = ((IdentNode)rhs).getName();
 
-            final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !rhs.getSymbol().isTopLevel());
+            final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !isProgramLevelSymbol(name));
 
             if (failDelete && rhs.getSymbol().isThis()) {
                 return LiteralNode.newInstance(unaryNode, true).accept(this);
@@ -797,7 +857,7 @@
             final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this);
 
             if (!failDelete) {
-                args.add(currentFunctionNode.getScopeNode());
+                args.add(compilerConstant(SCOPE));
             }
             args.add(literalNode);
             args.add(strictFlagNode);
@@ -825,42 +885,62 @@
             return LiteralNode.newInstance(unaryNode, true).accept(this);
         }
 
-        runtimeNode = new RuntimeNode(unaryNode, request, args);
-        assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this
+        final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, request, args);
+        assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //unary parent constructor should do this
 
         return leaveRuntimeNode(runtimeNode);
     }
 
+    /**
+     * Is the symbol denoted by the specified name in the current lexical context defined in the program level
+     * @param name the name of the symbol
+     * @return true if the symbol denoted by the specified name in the current lexical context defined in the program level.
+     */
+    private boolean isProgramLevelSymbol(final String name) {
+        for(final Iterator<Block> it = getLexicalContext().getBlocks(); it.hasNext();) {
+            final Block next = it.next();
+            if(next.getExistingSymbol(name) != null) {
+                return next == getLexicalContext().getFunctionBody(getLexicalContext().getOutermostFunction());
+            }
+        }
+        throw new AssertionError("Couldn't find symbol " + name + " in the context");
+    }
+
     @Override
     public Node leaveNEW(final UnaryNode unaryNode) {
-        newTemporary(Type.OBJECT, unaryNode);
+        ensureSymbol(Type.OBJECT, unaryNode);
         end(unaryNode);
         return unaryNode;
     }
 
     @Override
     public Node leaveNOT(final UnaryNode unaryNode) {
-        newTemporary(Type.BOOLEAN, unaryNode);
+        ensureSymbol(Type.BOOLEAN, unaryNode);
         end(unaryNode);
         return unaryNode;
     }
 
+    private IdentNode compilerConstant(CompilerConstants cc) {
+        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+        final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
+        node.setSymbol(functionNode.compilerConstant(cc));
+        return node;
+    }
+
     @Override
     public Node leaveTYPEOF(final UnaryNode unaryNode) {
-        final Node rhs    = unaryNode.rhs();
-
-        RuntimeNode runtimeNode;
+        final Node rhs = unaryNode.rhs();
 
         List<Node> args = new ArrayList<>();
         if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
-            args.add(getCurrentFunctionNode().getScopeNode());
+            args.add(compilerConstant(SCOPE));
             args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
         } else {
             args.add(rhs);
             args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
         }
 
-        runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
+        RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
         assert runtimeNode.getSymbol() == unaryNode.getSymbol();
 
         runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode);
@@ -872,21 +952,20 @@
 
     @Override
     public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
-        newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
+        ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode);
         return runtimeNode;
     }
 
     @Override
     public Node leaveSUB(final UnaryNode unaryNode) {
-        newTemporary(arithType(), unaryNode);
+        ensureSymbol(arithType(), unaryNode);
         end(unaryNode);
         return unaryNode;
     }
 
     @Override
     public Node leaveVOID(final UnaryNode unaryNode) {
-        final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.VOID);
-        runtimeNode.accept(this);
+        final RuntimeNode runtimeNode = (RuntimeNode)new RuntimeNode(unaryNode, Request.VOID).accept(this);
         assert runtimeNode.getSymbol().getSymbolType().isObject();
         end(unaryNode);
         return runtimeNode;
@@ -903,7 +982,7 @@
 
         ensureTypeNotUnknown(lhs);
         ensureTypeNotUnknown(rhs);
-        newTemporary(Type.widest(lhs.getType(), rhs.getType()), binaryNode);
+        ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode);
 
         end(binaryNode);
 
@@ -912,7 +991,7 @@
 
     @Override
     public Node leaveAND(final BinaryNode binaryNode) {
-        newTemporary(Type.OBJECT, binaryNode);
+        ensureSymbol(Type.OBJECT, binaryNode);
         end(binaryNode);
         return binaryNode;
     }
@@ -921,39 +1000,39 @@
      * This is a helper called before an assignment.
      * @param binaryNode assignment node
      */
-    private Node enterAssignmentNode(final BinaryNode binaryNode) {
+    private boolean enterAssignmentNode(final BinaryNode binaryNode) {
         start(binaryNode);
 
         final Node lhs = binaryNode.lhs();
 
         if (lhs instanceof IdentNode) {
-            final Block     block = getCurrentBlock();
+            final Block     block = getLexicalContext().getCurrentBlock();
             final IdentNode ident = (IdentNode)lhs;
             final String    name  = ident.getName();
 
-            Symbol symbol = findSymbol(getCurrentBlock(), name);
+            Symbol symbol = findSymbol(block, name);
 
             if (symbol == null) {
                 symbol = defineSymbol(block, name, IS_GLOBAL, ident);
                 binaryNode.setSymbol(symbol);
-            } else if (!isLocal(getCurrentFunctionNode(), symbol)) {
-                symbol.setIsScope();
+            } else {
+                maybeForceScope(symbol);
             }
 
             addLocalDef(name);
         }
 
-        return binaryNode;
+        return true;
     }
 
     private boolean isLocal(FunctionNode function, Symbol symbol) {
-        final Block block = symbol.getBlock();
-        // some temp symbols have no block, so can be assumed local
-        return block == null || lexicalContext.getFunction(block) == function;
+        final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol);
+        // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local
+        return definingFn == null || definingFn == function;
     }
 
     @Override
-    public Node enterASSIGN(final BinaryNode binaryNode) {
+    public boolean enterASSIGN(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -963,7 +1042,7 @@
     }
 
     @Override
-    public Node enterASSIGN_ADD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_ADD(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -978,7 +1057,7 @@
     }
 
     @Override
-    public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -988,7 +1067,7 @@
     }
 
     @Override
-    public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -998,7 +1077,7 @@
     }
 
     @Override
-    public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1008,7 +1087,7 @@
     }
 
     @Override
-    public Node enterASSIGN_DIV(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_DIV(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1018,7 +1097,7 @@
     }
 
     @Override
-    public Node enterASSIGN_MOD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MOD(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1028,7 +1107,7 @@
     }
 
     @Override
-    public Node enterASSIGN_MUL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MUL(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1038,7 +1117,7 @@
     }
 
     @Override
-    public Node enterASSIGN_SAR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SAR(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1048,7 +1127,7 @@
     }
 
     @Override
-    public Node enterASSIGN_SHL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHL(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1058,7 +1137,7 @@
     }
 
     @Override
-    public Node enterASSIGN_SHR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHR(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1068,7 +1147,7 @@
     }
 
     @Override
-    public Node enterASSIGN_SUB(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SUB(final BinaryNode binaryNode) {
         return enterAssignmentNode(binaryNode);
     }
 
@@ -1094,13 +1173,13 @@
 
     @Override
     public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
-        newTemporary(binaryNode.rhs().getType(), binaryNode);
+        ensureSymbol(binaryNode.rhs().getType(), binaryNode);
         return binaryNode;
     }
 
     @Override
     public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
-        newTemporary(binaryNode.lhs().getType(), binaryNode);
+        ensureSymbol(binaryNode.lhs().getType(), binaryNode);
         return binaryNode;
     }
 
@@ -1113,7 +1192,7 @@
         final Node lhs = binaryNode.lhs();
         final Node rhs = binaryNode.rhs();
 
-        newTemporary(Type.BOOLEAN, binaryNode);
+        ensureSymbol(Type.BOOLEAN, binaryNode);
         ensureTypeNotUnknown(lhs);
         ensureTypeNotUnknown(rhs);
 
@@ -1131,7 +1210,7 @@
 
         //newType(binaryNode.lhs().getSymbol(), operandType);
         //newType(binaryNode.rhs().getSymbol(), operandType);
-        newTemporary(destType, binaryNode);
+        ensureSymbol(destType, binaryNode);
         return binaryNode;
     }
 
@@ -1216,7 +1295,7 @@
 
     @Override
     public Node leaveOR(final BinaryNode binaryNode) {
-        newTemporary(Type.OBJECT, binaryNode);
+        ensureSymbol(Type.OBJECT, binaryNode);
         end(binaryNode);
         return binaryNode;
     }
@@ -1244,7 +1323,7 @@
     @Override
     public Node leaveForNode(final ForNode forNode) {
         if (forNode.isForIn()) {
-            forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
+            forNode.setIterator(newInternal(getLexicalContext().getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73
             /*
              * Iterators return objects, so we need to widen the scope of the
              * init variable if it, for example, has been assigned double type
@@ -1267,65 +1346,50 @@
         ensureTypeNotUnknown(rhs);
 
         final Type type = Type.widest(lhs.getType(), rhs.getType());
-        newTemporary(type, ternaryNode);
+        ensureSymbol(type, ternaryNode);
 
         end(ternaryNode);
+        assert ternaryNode.getSymbol() != null;
 
         return ternaryNode;
     }
 
-    private void initThis(final FunctionNode functionNode) {
-        final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null);
+    private void initThis(final Block block) {
+        final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null);
         newType(thisSymbol, Type.OBJECT);
         thisSymbol.setNeedsSlot(true);
-        functionNode.getThisNode().setSymbol(thisSymbol);
-        LOG.info("Initialized scope symbol: " + thisSymbol);
     }
 
-    private void initScope(final FunctionNode functionNode) {
-        final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
+    private void initScope(final Block block) {
+        final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null);
         newType(scopeSymbol, Type.typeFor(ScriptObject.class));
         scopeSymbol.setNeedsSlot(true);
-        functionNode.getScopeNode().setSymbol(scopeSymbol);
-        LOG.info("Initialized scope symbol: " + scopeSymbol);
     }
 
-    private void initReturn(final FunctionNode functionNode) {
-        final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
+    private void initReturn(final Block block) {
+        final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null);
         newType(returnSymbol, Type.OBJECT);
         returnSymbol.setNeedsSlot(true);
-        functionNode.getResultNode().setSymbol(returnSymbol);
-        LOG.info("Initialized return symbol: " + returnSymbol);
         //return symbol is always object as it's the __return__ thing. What returnType is is another matter though
     }
 
-    private void initVarArg(final FunctionNode functionNode) {
-        if (functionNode.isVarArg()) {
-            final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
-            varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
-            varArgsSymbol.setNeedsSlot(true);
-            functionNode.getVarArgsNode().setSymbol(varArgsSymbol);
-            LOG.info("Initialized varargs symbol: " + varArgsSymbol);
+    private void initVarArg(final Block block, final boolean needsArguments) {
+        final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null);
+        varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
+        varArgsSymbol.setNeedsSlot(true);
 
-            if (functionNode.needsArguments()) {
-                final String    argumentsName   = functionNode.getArgumentsNode().getName();
-                final Symbol    argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null);
-                newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
-                argumentsSymbol.setNeedsSlot(true);
-                functionNode.getArgumentsNode().setSymbol(argumentsSymbol);
-                addLocalDef(argumentsName);
-                LOG.info("Initialized vararg varArgsSymbol=" + varArgsSymbol + " argumentsSymbol=" + argumentsSymbol);
-            }
+        if (needsArguments) {
+            final Symbol    argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null);
+            newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
+            argumentsSymbol.setNeedsSlot(true);
+            addLocalDef(ARGUMENTS.symbolName());
         }
     }
 
-    private void initCallee(final FunctionNode functionNode) {
-        assert functionNode.getCalleeNode() != null : functionNode + " has no callee";
-        final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
-        newType(calleeSymbol, Type.typeFor(ScriptFunction.class));
+    private void initCallee(final Block block) {
+        final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null);
+        newType(calleeSymbol, FunctionNode.FUNCTION_TYPE);
         calleeSymbol.setNeedsSlot(true);
-        functionNode.getCalleeNode().setSymbol(calleeSymbol);
-        LOG.info("Initialized callee symbol " + calleeSymbol);
     }
 
     /**
@@ -1334,25 +1398,19 @@
      *
      * @param functionNode the function node
      */
-    private void initParameters(final FunctionNode functionNode) {
-        //If a function is specialized, we don't need to tag either it return
-        // type or its parameters with the widest (OBJECT) type for safety.
-        functionNode.setReturnType(Type.UNKNOWN);
-
+    private void initParameters(final FunctionNode functionNode, final Block body) {
         for (final IdentNode param : functionNode.getParameters()) {
             addLocalDef(param.getName());
-            final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param);
+            final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param);
             if (paramSymbol != null) {
                 final Type callSiteParamType = functionNode.getSpecializedType(param);
                 if (callSiteParamType != null) {
-                    LOG.info("Param " + paramSymbol + " has a callsite type " + callSiteParamType + ". Using that.");
-
-                    System.err.println("Param " + param + " has a callsite type " + callSiteParamType + ". Using that.");
+                    LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that.");
                 }
                 newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType);
             }
 
-            LOG.info("Initialized param " + paramSymbol);
+            LOG.info("Initialized param ", paramSymbol);
         }
     }
 
@@ -1378,7 +1436,7 @@
             // this function, we can tell the runtime system that no matter what the
             // call site is, use this information. TODO
             if (!paramSymbol.getSymbolType().isObject()) {
-                LOG.finest("Parameter " + ident + " could profit from specialization to " + paramSymbol.getSymbolType());
+                LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType());
             }
 
             newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType()));
@@ -1392,19 +1450,18 @@
 
     /**
      * Move any properties from a global map into the scope of this method
-     * @param functionNode the function node for which to init scope vars
+     * @param block the function node body for which to init scope vars
      */
-    private void initFromPropertyMap(final FunctionNode functionNode) {
+    private void initFromPropertyMap(final Block block) {
         // For a script, add scope symbols as defined in the property map
-        assert functionNode.isProgram();
 
         final PropertyMap map = Context.getGlobalMap();
 
         for (final Property property : map.getProperties()) {
             final String key    = property.getKey();
-            final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null);
+            final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null);
             newType(symbol, Type.OBJECT);
-            LOG.info("Added global symbol from property map " + symbol);
+            LOG.info("Added global symbol from property map ", symbol);
         }
     }
 
@@ -1412,7 +1469,7 @@
 
         final Symbol symbol = node.getSymbol();
 
-        LOG.info("Ensure type not unknown for: " + symbol);
+        LOG.info("Ensure type not unknown for: ", symbol);
 
         /*
          * Note that not just unknowns, but params need to be blown
@@ -1452,7 +1509,7 @@
     }
 
     private Symbol exceptionSymbol() {
-        return newInternal(getCurrentFunctionNode().uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class));
+        return newInternal(getLexicalContext().getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class));
     }
 
     /**
@@ -1512,15 +1569,15 @@
                     }
                     Type from = node.getType();
                     if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) {
-                        LOG.fine("Had to post pass widen '" + node + "' " + Debug.id(node) + " from " + node.getType() + " to " + to);
+                        LOG.fine("Had to post pass widen '", node, "' " + Debug.id(node), " from ", node.getType(), " to ", to);
                         newType(node.getSymbol(), to);
                         changed.add(node);
                     }
                 }
 
                 @Override
-                public Node enterFunctionNode(final FunctionNode node) {
-                    return node.isLazy() ? null : node;
+                public boolean enterFunctionNode(final FunctionNode node) {
+                    return !node.isLazy();
                 }
 
                 /**
@@ -1574,7 +1631,7 @@
         } else {
             type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too.
         }
-        newTemporary(type, binaryNode);
+        ensureSymbol(type, binaryNode);
         newType(lhs.getSymbol(), type);
         end(binaryNode);
         return binaryNode;
@@ -1589,32 +1646,25 @@
         final Node lhs = binaryNode.lhs();
 
         newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
-        newTemporary(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
+        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
 
-        ensureAssignmentSlots(getCurrentFunctionNode(), binaryNode);
+        ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode);
 
         end(binaryNode);
         return binaryNode;
     }
 
-    private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
-        if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
-            return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName());
-        }
-        return false;
+    private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) {
+        LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type);
+        return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node);
     }
 
-    private static Symbol newTemporary(final FunctionNode functionNode, final Type type, final Node node) {
-        LOG.info("New TEMPORARY added to " + functionNode.getName() + " type=" + type);
-        return functionNode.newTemporary(type, node);
-    }
-
-    private Symbol newTemporary(final Type type, final Node node) {
-        return newTemporary(getCurrentFunctionNode(), type, node);
+    private Symbol ensureSymbol(final Type type, final Node node) {
+        return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node);
     }
 
     private Symbol newInternal(final String name, final Type type) {
-        final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null);
+        final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null);
         iter.setType(type); // NASHORN-73
         return iter;
     }
@@ -1624,40 +1674,51 @@
         symbol.setType(type);
 
         if (symbol.getSymbolType() != oldType) {
-            LOG.info("New TYPE " + type + " for " + symbol + " (was " + oldType + ")");
+            LOG.info("New TYPE ", type, " for ", symbol," (was ", oldType, ")");
         }
 
         if (symbol.isParam()) {
             symbol.setType(type);
-            LOG.info("Param type change " + symbol);
+            LOG.info("Param type change ", symbol);
         }
     }
 
-    private void clearLocalDefs() {
-        localDefs = new HashSet<>();
+    private void pushLocalsFunction() {
+        localDefs.push(new HashSet<String>());
+        localUses.push(new HashSet<String>());
+    }
+
+    private void pushLocalsBlock() {
+        localDefs.push(localDefs.isEmpty() ? new HashSet<String>() : new HashSet<>(localDefs.peek()));
+        localUses.push(localUses.isEmpty() ? new HashSet<String>() : new HashSet<>(localUses.peek()));
+    }
+
+    private void popLocals() {
+        localDefs.pop();
+        localUses.pop();
     }
 
     private boolean isLocalDef(final String name) {
-        return localDefs.contains(name);
+        return localDefs.peek().contains(name);
     }
 
     private void addLocalDef(final String name) {
-        LOG.info("Adding local def of symbol: '" + name + "'");
-        localDefs.add(name);
+        LOG.info("Adding local def of symbol: '", name, "'");
+        localDefs.peek().add(name);
     }
 
     private void removeLocalDef(final String name) {
-        LOG.info("Removing local def of symbol: '" + name + "'");
-        localDefs.remove(name);
+        LOG.info("Removing local def of symbol: '", name, "'");
+        localDefs.peek().remove(name);
     }
 
-    private void clearLocalUses() {
-        localUses = new HashSet<>();
+    private boolean isLocalUse(final String name) {
+        return localUses.peek().contains(name);
     }
 
     private void addLocalUse(final String name) {
-        LOG.info("Adding local use of symbol: '" + name + "'");
-        localUses.add(name);
+        LOG.info("Adding local use of symbol: '", name, "'");
+        localUses.peek().add(name);
     }
 
     /**
@@ -1665,30 +1726,28 @@
      * This is done when the function contains unevaluated black boxes such as
      * lazy sub-function nodes that have not been compiled.
      *
-     * @param functionNode function node in whose scope symbols should conservatively be made objects
+     * @param body body for the function node we are leaving
      */
-    private static void objectifySymbols(final FunctionNode functionNode) {
-        functionNode.accept(new NodeVisitor() {
+    private static void objectifySymbols(final Block body) {
+        body.accept(new NodeVisitor() {
             private void toObject(final Block block) {
                 for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) {
                     final Symbol symbol = iter.next();
-                    newType(symbol, Type.OBJECT);
+                    if (!symbol.isTemp()) {
+                        newType(symbol, Type.OBJECT);
+                    }
                 }
             }
 
             @Override
-            public Node enterBlock(final Block block) {
+            public boolean enterBlock(final Block block) {
                 toObject(block);
-                return block;
+                return true;
             }
 
             @Override
-            public Node enterFunctionNode(final FunctionNode node) {
-                toObject(node);
-                if (node.isLazy()) {
-                    return null;
-                }
-                return node;
+            public boolean enterFunctionNode(final FunctionNode node) {
+                return false;
             }
         });
     }
@@ -1702,11 +1761,11 @@
         return cn.substring(lastDot + 1);
     }
 
-    private Node start(final Node node) {
+    private boolean start(final Node node) {
         return start(node, true);
     }
 
-    private Node start(final Node node, final boolean printNode) {
+    private boolean start(final Node node, final boolean printNode) {
         if (DEBUG) {
             final StringBuilder sb = new StringBuilder();
 
@@ -1715,13 +1774,13 @@
                 append("] ").
                 append(printNode ? node.toString() : "").
                 append(" in '").
-                append(getCurrentFunctionNode().getName()).
+                append(getLexicalContext().getCurrentFunction().getName()).
                 append("'");
-            LOG.info(sb.toString());
+            LOG.info(sb);
             LOG.indent();
         }
 
-        return node;
+        return true;
     }
 
     private Node end(final Node node) {
@@ -1737,7 +1796,7 @@
                 append("] ").
                 append(printNode ? node.toString() : "").
                 append(" in '").
-                append(getCurrentFunctionNode().getName());
+                append(getLexicalContext().getCurrentFunction().getName());
 
             if (node.getSymbol() == null) {
                 sb.append(" <NO SYMBOL>");
@@ -1746,7 +1805,7 @@
             }
 
             LOG.unindent();
-            LOG.info(sb.toString());
+            LOG.info(sb);
         }
 
         return node;
--- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java	Thu May 16 11:47:51 2013 +0100
@@ -58,12 +58,14 @@
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
+
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -219,14 +221,14 @@
     private void defineCommonStatics(final boolean strictMode) {
         // source - used to store the source data (text) for this script.  Shared across
         // compile units.  Set externally by the compiler.
-        field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.tag(), Source.class);
+        field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.symbolName(), Source.class);
 
         // constants - used to the constants array for this script.  Shared across
         // compile units.  Set externally by the compiler.
-        field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.tag(), Object[].class);
+        field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.symbolName(), Object[].class);
 
         // strictMode - was this script compiled in strict mode.  Set externally by the compiler.
-        field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.tag(), boolean.class, strictMode);
+        field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.symbolName(), boolean.class, strictMode);
     }
 
     /**
@@ -238,9 +240,9 @@
 
         if (constantMethodNeeded.contains(String.class)) {
             // $getString - get the ith entry from the constants table and cast to String.
-            final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.tag(), String.class, int.class);
+            final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.symbolName(), String.class, int.class);
             getStringMethod.begin();
-            getStringMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor())
+            getStringMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor())
                         .load(Type.INT, 0)
                         .arrayload()
                         .checkcast(String.class)
@@ -250,7 +252,7 @@
 
         if (constantMethodNeeded.contains(PropertyMap.class)) {
             // $getMap - get the ith entry from the constants table and cast to PropertyMap.
-            final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class);
+            final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.symbolName(), PropertyMap.class, int.class);
             getMapMethod.begin();
             getMapMethod.loadConstants()
                         .load(Type.INT, 0)
@@ -260,7 +262,7 @@
             getMapMethod.end();
 
             // $setMap - overwrite an existing map.
-            final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class);
+            final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.symbolName(), void.class, int.class, PropertyMap.class);
             setMapMethod.begin();
             setMapMethod.loadConstants()
                         .load(Type.INT, 0)
@@ -289,7 +291,7 @@
         final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class);
 
         getArrayMethod.begin();
-        getArrayMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor())
+        getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor())
                       .load(Type.INT, 0)
                       .arrayload()
                       .checkcast(cls)
@@ -307,7 +309,7 @@
      */
     static String getArrayMethodName(final Class<?> cls) {
         assert cls.isArray();
-        return GET_ARRAY_PREFIX.tag() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.tag();
+        return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName();
     }
 
     /**
@@ -409,6 +411,10 @@
         methodsStarted.remove(method);
     }
 
+    SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
+        return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode);
+    }
+
     /**
      * Add a new method to the class - defaults to public method
      *
@@ -433,7 +439,7 @@
      * @return method emitter to use for weaving this method
      */
     MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
-        return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null));
+        return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes));
     }
 
     /**
@@ -484,7 +490,7 @@
      * @return method emitter to use for weaving <clinit>
      */
     MethodEmitter clinit() {
-        return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class);
+        return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class);
     }
 
     /**
@@ -493,7 +499,7 @@
      * @return method emitter to use for weaving <init>()V
      */
     MethodEmitter init() {
-        return method(INIT.tag(), void.class);
+        return method(INIT.symbolName(), void.class);
     }
 
     /**
@@ -503,7 +509,7 @@
      * @return method emitter to use for weaving <init>()V
      */
     MethodEmitter init(final Class<?>... ptypes) {
-        return method(INIT.tag(), void.class, ptypes);
+        return method(INIT.symbolName(), void.class, ptypes);
     }
 
     /**
@@ -515,7 +521,7 @@
      * @return method emitter to use for weaving <init>(...)V
      */
     MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) {
-        return method(flags, INIT.tag(), void.class, ptypes);
+        return method(flags, INIT.symbolName(), void.class, ptypes);
     }
 
     /**
@@ -628,4 +634,9 @@
             return v;
         }
     }
+
+    private MethodVisitor methodVisitor(EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) {
+        return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null);
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu May 16 11:47:51 2013 +0100
@@ -27,14 +27,18 @@
 
 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE;
 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC;
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP;
 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING;
-import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF;
 import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX;
+import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
+import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
@@ -48,8 +52,10 @@
 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Deque;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -67,11 +73,11 @@
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.BreakNode;
+import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -81,10 +87,12 @@
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.LexicalContextNode;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
+import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyNode;
@@ -107,8 +115,10 @@
 import jdk.nashorn.internal.parser.Lexer.RegexToken;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ECMAException;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
@@ -157,14 +167,29 @@
     /** How many regexp fields have been emitted */
     private int regexFieldCount;
 
-    /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling
-     * a just-defined anonymous function expression. */
-    private boolean functionNodeIsCallee;
-
     /** Map of shared scope call sites */
     private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
 
-    private final LexicalContext lexicalContext = new LexicalContext();
+    /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */
+    private final Deque<CompileUnit> compileUnits = new ArrayDeque<>();
+
+    /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
+    private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
+
+    /** The discard stack - whenever we enter a discard node we keep track of its return value status -
+     *  i.e. should we keep it or throw it away */
+    private final Deque<Node> discard = new ArrayDeque<>();
+
+    // A stack tracking the next free local variable slot in the blocks. There's one entry for every block
+    // currently on the lexical context stack.
+    private int[] nextFreeSlots = new int[16];
+    private int nextFreeSlotsSize = 0;
+
+    /** Current method emitter */
+    private MethodEmitter method;
+
+    /** Current compile unit */
+    private CompileUnit unit;
 
     /** When should we stop caching regexp expressions in fields to limit bytecode size? */
     private static final int MAX_REGEX_FIELDS = 2 * 1024;
@@ -177,6 +202,7 @@
      * @param compiler
      */
     CodeGenerator(final Compiler compiler) {
+        super(new DynamicScopeTrackingLexicalContext());
         this.compiler      = compiler;
         this.callSiteFlags = compiler.getEnv()._callsite_flags;
     }
@@ -188,7 +214,37 @@
      * @return the correct flags for a call site in the current function
      */
     int getCallSiteFlags() {
-        return getCurrentFunctionNode().isStrictMode() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags;
+        return getLexicalContext().getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags;
+    }
+
+    private void pushMethodEmitter(final MethodEmitter newMethod) {
+        methodEmitters.push(newMethod);
+        this.method = newMethod;
+    }
+
+    private void popMethodEmitter(final MethodEmitter oldMethod) {
+        assert methodEmitters.peek() == oldMethod;
+        methodEmitters.pop();
+        if (!methodEmitters.isEmpty()) {
+            this.method = methodEmitters.peek();
+        } else {
+            this.method = null;
+        }
+    }
+
+    private void push(final CompileUnit newUnit) {
+        compileUnits.push(newUnit);
+        this.unit = newUnit;
+    }
+
+    private void pop(final CompileUnit oldUnit) {
+        assert compileUnits.peek() == oldUnit;
+        compileUnits.pop();
+        if (!compileUnits.isEmpty()) {
+            this.unit = compileUnits.peek();
+        } else {
+            this.unit = null;
+        }
     }
 
     /**
@@ -217,7 +273,7 @@
             assert identNode.getSymbol().isScope() : identNode + " is not in scope!";
 
             final int flags = CALLSITE_SCOPE | getCallSiteFlags();
-            method.loadScope();
+            method.loadCompilerConstant(SCOPE);
 
             if (isFastScope(symbol)) {
                 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
@@ -231,27 +287,103 @@
     }
 
     /**
+     * A lexical context that also tracks if we have any dynamic scopes in the context. Such scopes can have new
+     * variables introduced into them at run time - a with block or a function directly containing an eval call.
+     */
+    private static class DynamicScopeTrackingLexicalContext extends LexicalContext {
+        int dynamicScopeCount = 0;
+
+        @Override
+        public <T extends LexicalContextNode> T push(T node) {
+            if(isDynamicScopeBoundary(node)) {
+                ++dynamicScopeCount;
+            }
+            return super.push(node);
+        }
+
+        @Override
+        public <T extends LexicalContextNode> T pop(T node) {
+            final T popped = super.pop(node);
+            if(isDynamicScopeBoundary(popped)) {
+                --dynamicScopeCount;
+            }
+            return popped;
+        }
+
+        private boolean isDynamicScopeBoundary(LexicalContextNode node) {
+            if(node instanceof Block) {
+                // Block's immediate parent is a with node. Note we aren't testing for a WithNode, as that'd capture
+                // processing of WithNode.expression too, but it should be unaffected.
+                return !isEmpty() && peek() instanceof WithNode;
+            } else if(node instanceof FunctionNode) {
+                // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
+                // variable into the function's scope), and it isn't strict (as evals in strict functions get an
+                // isolated scope).
+                return isFunctionDynamicScope((FunctionNode)node);
+            }
+            return false;
+        }
+    }
+
+    boolean inDynamicScope() {
+        return ((DynamicScopeTrackingLexicalContext)getLexicalContext()).dynamicScopeCount > 0;
+    }
+
+    static boolean isFunctionDynamicScope(FunctionNode fn) {
+        return fn.hasEval() && !fn.isStrict();
+    }
+
+    /**
      * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
      *
      * @param function function to check for fast scope
      * @return true if fast scope
      */
     private boolean isFastScope(final Symbol symbol) {
-        if (!symbol.isScope() || !symbol.getBlock().needsScope()) {
+        if(!symbol.isScope()) {
+            return false;
+        }
+        final LexicalContext lc = getLexicalContext();
+        if(!inDynamicScope()) {
+            // If there's no with or eval in context, and the symbol is marked as scoped, it is fast scoped. Such a
+            // symbol must either be global, or its defining block must need scope.
+            assert symbol.isGlobal() || lc.getDefiningBlock(symbol).needsScope() : symbol.getName();
+            return true;
+        }
+        if(symbol.isGlobal()) {
+            // Shortcut: if there's a with or eval in context, globals can't be fast scoped
             return false;
         }
-        // Allow fast scope access if no function contains with or eval
-        for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) {
-            final FunctionNode func = it.next();
-            if (func.hasWith() || func.hasEval()) {
-                return false;
+        // Otherwise, check if there's a dynamic scope between use of the symbol and its definition
+        final String name = symbol.getName();
+        boolean previousWasBlock = false;
+        for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
+            final LexicalContextNode node = it.next();
+            if(node instanceof Block) {
+                // If this block defines the symbol, then we can fast scope the symbol.
+                final Block block = (Block)node;
+                if(block.getExistingSymbol(name) == symbol) {
+                    assert block.needsScope();
+                    return true;
+                }
+                previousWasBlock = true;
+            } else {
+                if((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && isFunctionDynamicScope((FunctionNode)node))) {
+                    // If we hit a scope that can have symbols introduced into it at run time before finding the defining
+                    // block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block
+                    // before - its block. Otherwise, we are currently processing the WithNode's expression, and that's
+                    // obviously not subjected to introducing new symbols.
+                    return false;
+                }
+                previousWasBlock = false;
             }
         }
-        return true;
+        // Should've found the symbol defined in a block
+        throw new AssertionError();
     }
 
     private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
-        method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
+        method.load(isFastScope(symbol) ? getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol) : -1);
         final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE);
         scopeCall.generateInvoke(method);
         return method;
@@ -271,10 +403,10 @@
 
     private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
         int depth = 0;
-        final Block definingBlock = symbol.getBlock();
-        for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) {
+        final String name = symbol.getName();
+        for(final Iterator<Block> blocks = getLexicalContext().getBlocks(startingBlock); blocks.hasNext();) {
             final Block currentBlock = blocks.next();
-            if (currentBlock == definingBlock) {
+            if (currentBlock.getExistingSymbol(name) == symbol) {
                 return depth;
             }
             if (currentBlock.needsScope()) {
@@ -285,9 +417,9 @@
     }
 
     private void loadFastScopeProto(final Symbol symbol, final boolean swap) {
-        final int depth = getScopeProtoDepth(getCurrentBlock(), symbol);
+        final int depth = getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol);
         assert depth != -1;
-        if(depth > 0) {
+        if (depth > 0) {
             if (swap) {
                 method.swap();
             }
@@ -328,46 +460,46 @@
          */
         final CodeGenerator codegen = this;
 
-        node.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
+        node.accept(new NodeVisitor() {
             @Override
-            public Node enterIdentNode(final IdentNode identNode) {
+            public boolean enterIdentNode(final IdentNode identNode) {
                 loadIdent(identNode);
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterAccessNode(final AccessNode accessNode) {
+            public boolean enterAccessNode(final AccessNode accessNode) {
                 if (!baseAlreadyOnStack) {
                     load(accessNode.getBase()).convert(Type.OBJECT);
                 }
                 assert method.peekType().isObject();
                 method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction());
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterIndexNode(final IndexNode indexNode) {
+            public boolean enterIndexNode(final IndexNode indexNode) {
                 if (!baseAlreadyOnStack) {
                     load(indexNode.getBase()).convert(Type.OBJECT);
                     load(indexNode.getIndex());
                 }
                 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction());
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterFunctionNode(FunctionNode functionNode) {
+            public boolean enterFunctionNode(FunctionNode functionNode) {
                 // function nodes will always leave a constructed function object on stack, no need to load the symbol
                 // separately as in enterDefault()
                 functionNode.accept(codegen);
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterDefault(final Node otherNode) {
+            public boolean enterDefault(final Node otherNode) {
                 otherNode.accept(codegen); // generate code for whatever we are looking at.
                 method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
-                return null;
+                return false;
             }
         });
 
@@ -375,14 +507,9 @@
     }
 
     @Override
-    public Node enterAccessNode(final AccessNode accessNode) {
-        if (accessNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterAccessNode(final AccessNode accessNode) {
         load(accessNode);
-
-        return null;
+        return false;
     }
 
     /**
@@ -407,7 +534,7 @@
             final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined();
 
             if (symbol.hasSlot() && !isInternal) {
-                assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getCurrentFunctionNode();
+                assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getLexicalContext().getCurrentFunction();
                 if (symbol.getSymbolType().isNumber()) {
                     numbers.add(symbol);
                 } else if (symbol.getSymbolType().isObject()) {
@@ -441,22 +568,20 @@
      * @param block block containing symbols.
      */
     private void symbolInfo(final Block block) {
-        for (final Symbol symbol : block.getFrame().getSymbols()) {
-            method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
+        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
+            final Symbol symbol = iter.next();
+            if (symbol.hasSlot()) {
+                method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel());
+            }
         }
     }
 
     @Override
-    public Node enterBlock(final Block block) {
-        if (block.testResolved()) {
-            return null;
-        }
-        lexicalContext.push(block);
-
+    public boolean enterBlock(final Block block) {
         method.label(block.getEntryLabel());
         initLocals(block);
 
-        return block;
+        return true;
     }
 
     @Override
@@ -464,10 +589,10 @@
         method.label(block.getBreakLabel());
         symbolInfo(block);
 
-        if (block.needsScope()) {
+        if (block.needsScope() && !block.isTerminal()) {
             popBlockScope(block);
         }
-        lexicalContext.pop(block);
+        --nextFreeSlotsSize;
         return block;
     }
 
@@ -477,34 +602,30 @@
         final Label skipLabel     = new Label("skip_catch");
 
         /* pop scope a la try-finally */
-        method.loadScope();
+        method.loadCompilerConstant(SCOPE);
         method.invoke(ScriptObject.GET_PROTO);
-        method.storeScope();
+        method.storeCompilerConstant(SCOPE);
         method._goto(skipLabel);
         method.label(exitLabel);
 
         method._catch(recoveryLabel);
-        method.loadScope();
+        method.loadCompilerConstant(SCOPE);
         method.invoke(ScriptObject.GET_PROTO);
-        method.storeScope();
+        method.storeCompilerConstant(SCOPE);
         method.athrow();
         method.label(skipLabel);
         method._try(block.getEntryLabel(), exitLabel, recoveryLabel, Throwable.class);
     }
 
     @Override
-    public Node enterBreakNode(final BreakNode breakNode) {
-        if (breakNode.testResolved()) {
-            return null;
-        }
-
-        for (int i = 0; i < breakNode.getScopeNestingLevel(); i++) {
+    public boolean enterBreakNode(final BreakNode breakNode) {
+        final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel());
+        for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) {
             closeWith();
         }
-
-        method.splitAwareGoto(breakNode.getTargetLabel());
-
-        return null;
+        method.splitAwareGoto(getLexicalContext(), breakFrom.getBreakLabel());
+
+        return false;
     }
 
     private int loadArgs(final List<Node> args) {
@@ -541,21 +662,17 @@
     }
 
     @Override
-    public Node enterCallNode(final CallNode callNode) {
-        if (callNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterCallNode(final CallNode callNode) {
         final List<Node>   args            = callNode.getArgs();
         final Node         function        = callNode.getFunction();
-        final Block        currentBlock    = getCurrentBlock();
-
-        function.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
+        final Block        currentBlock    = getLexicalContext().getCurrentBlock();
+
+        function.accept(new NodeVisitor() {
 
             private void sharedScopeCall(final IdentNode identNode, final int flags) {
                 final Symbol symbol = identNode.getSymbol();
                 int    scopeCallFlags = flags;
-                method.loadScope();
+                method.loadCompilerConstant(SCOPE);
                 if (isFastScope(symbol)) {
                     method.load(getScopeProtoDepth(currentBlock, symbol));
                     scopeCallFlags |= CALLSITE_FAST_SCOPE;
@@ -591,7 +708,7 @@
                 // We don't need ScriptFunction object for 'eval'
                 method.pop();
 
-                method.loadScope(); // Load up self (scope).
+                method.loadCompilerConstant(SCOPE); // Load up self (scope).
 
                 final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
                 // load evaluated code
@@ -618,7 +735,7 @@
             }
 
             @Override
-            public Node enterIdentNode(final IdentNode node) {
+            public boolean enterIdentNode(final IdentNode node) {
                 final Symbol symbol = node.getSymbol();
 
                 if (symbol.isScope()) {
@@ -626,27 +743,27 @@
                     final int useCount = symbol.getUseCount();
 
                     // Threshold for generating shared scope callsite is lower for fast scope symbols because we know
-                    // we can dial in the correct scope. However, we als need to enable it for non-fast scopes to
+                    // we can dial in the correct scope. However, we also need to enable it for non-fast scopes to
                     // support huge scripts like mandreel.js.
                     if (callNode.isEval()) {
                         evalCall(node, flags);
                     } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
                             || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
-                            || callNode.inWithBlock()) {
+                            || CodeGenerator.this.inDynamicScope()) {
                         scopeCall(node, flags);
                     } else {
                         sharedScopeCall(node, flags);
                     }
-                    assert method.peekType().equals(callNode.getType());
+                    assert method.peekType().equals(callNode.getType()) : method.peekType() + "!=" + callNode.getType();
                 } else {
                     enterDefault(node);
                 }
 
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterAccessNode(final AccessNode node) {
+            public boolean enterAccessNode(final AccessNode node) {
                 load(node.getBase());
                 method.convert(Type.OBJECT);
                 method.dup();
@@ -655,35 +772,34 @@
                 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
                 assert method.peekType().equals(callNode.getType());
 
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterFunctionNode(final FunctionNode callee) {
+            public boolean enterFunctionNode(final FunctionNode origCallee) {
+                // NOTE: visiting the callee will leave a constructed ScriptFunction object on the stack if
+                // callee.needsCallee() == true
+                final FunctionNode callee = (FunctionNode)origCallee.accept(CodeGenerator.this);
+
                 final boolean      isVarArg = callee.isVarArg();
                 final int          argCount = isVarArg ? -1 : callee.getParameters().size();
 
                 final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString();
 
-                if (callee.needsCallee()) {
-                    newFunctionObject(callee);
-                }
-
-                if (callee.isStrictMode()) { // self is undefined
+                if (callee.isStrict()) { // self is undefined
                     method.loadUndefined(Type.OBJECT);
                 } else { // get global from scope (which is the self)
                     globalInstance();
                 }
                 loadArgs(args, signature, isVarArg, argCount);
+                assert callee.getCompileUnit() != null : "no compile unit for " + callee.getName() + " " + Debug.id(callee) + " " + callNode;
                 method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
                 assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
-                functionNodeIsCallee = true;
-                callee.accept(CodeGenerator.this);
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterIndexNode(final IndexNode node) {
+            public boolean enterIndexNode(final IndexNode node) {
                 load(node.getBase());
                 method.convert(Type.OBJECT);
                 method.dup();
@@ -697,11 +813,11 @@
                 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
                 assert method.peekType().equals(callNode.getType());
 
-                return null;
+                return false;
             }
 
             @Override
-            protected Node enterDefault(final Node node) {
+            protected boolean enterDefault(final Node node) {
                 // Load up function.
                 load(function);
                 method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions
@@ -709,58 +825,41 @@
                 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
                 assert method.peekType().equals(callNode.getType());
 
-                return null;
+                return false;
             }
         });
 
         method.store(callNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterContinueNode(final ContinueNode continueNode) {
-        if (continueNode.testResolved()) {
-            return null;
-        }
-
-        for (int i = 0; i < continueNode.getScopeNestingLevel(); i++) {
+    public boolean enterContinueNode(final ContinueNode continueNode) {
+        final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel());
+        for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) {
             closeWith();
         }
-
-        method.splitAwareGoto(continueNode.getTargetLabel());
-
-        return null;
+        method.splitAwareGoto(getLexicalContext(), continueTo.getContinueLabel());
+
+        return false;
     }
 
     @Override
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        return enterWhileNode(doWhileNode);
-    }
-
-    @Override
-    public Node enterEmptyNode(final EmptyNode emptyNode) {
-        return null;
+    public boolean enterEmptyNode(final EmptyNode emptyNode) {
+        return false;
     }
 
     @Override
-    public Node enterExecuteNode(final ExecuteNode executeNode) {
-        if (executeNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterExecuteNode(final ExecuteNode executeNode) {
         final Node expression = executeNode.getExpression();
         expression.accept(this);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterForNode(final ForNode forNode) {
-        if (forNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterForNode(final ForNode forNode) {
         final Node  test   = forNode.getTest();
         final Block body   = forNode.getBody();
         final Node  modify = forNode.getModify();
@@ -790,6 +889,10 @@
 
             new Store<Node>(init) {
                 @Override
+                protected void storeNonDiscard() {
+                    return;
+                }
+                @Override
                 protected void evaluate() {
                     method.load(iter);
                     method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class));
@@ -829,7 +932,19 @@
             method.label(breakLabel);
         }
 
-        return null;
+        return false;
+    }
+
+    private static int assignSlots(final Block block, final int firstSlot) {
+        int nextSlot = firstSlot;
+        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
+            final Symbol next = iter.next();
+            if (next.hasSlot()) {
+                next.setSlot(nextSlot);
+                nextSlot += next.slotCount();
+            }
+        }
+        return nextSlot;
     }
 
     /**
@@ -838,21 +953,26 @@
      * @param block block with local vars.
      */
     private void initLocals(final Block block) {
-        final FunctionNode function       = lexicalContext.getFunction(block);
-        final boolean      isFunctionNode = block == function;
-
-        /*
-         * Get the symbols from the frame and realign the frame so that all
-         * slots get correct numbers. The slot numbering is not fixed until
-         * after initLocals has been run
-         */
-        final Frame        frame   = block.getFrame();
-        final List<Symbol> symbols = frame.getSymbols();
-
-        /* Fix the predefined slots so they have numbers >= 0, like varargs. */
-        frame.realign();
-
-        if (isFunctionNode) {
+        final boolean isFunctionBody = getLexicalContext().isFunctionBody();
+
+        final int nextFreeSlot;
+        if (isFunctionBody) {
+            // On entry to function, start with slot 0
+            nextFreeSlot = 0;
+        } else {
+            // Otherwise, continue from previous block's first free slot
+            nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1];
+        }
+        if(nextFreeSlotsSize == nextFreeSlots.length) {
+            final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2];
+            System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize);
+            nextFreeSlots = newNextFreeSlots;
+        }
+        nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot);
+
+        final FunctionNode function = getLexicalContext().getCurrentFunction();
+        if (isFunctionBody) {
+            /* Fix the predefined slots so they have numbers >= 0, like varargs. */
             if (function.needsParentScope()) {
                 initParentScope();
             }
@@ -876,14 +996,18 @@
             final List<String> nameList = new ArrayList<>();
             final List<Symbol> locals   = new ArrayList<>();
 
-
             // Initalize symbols and values
             final List<Symbol> newSymbols = new ArrayList<>();
             final List<Symbol> values     = new ArrayList<>();
 
             final boolean hasArguments = function.needsArguments();
-            for (final Symbol symbol : symbols) {
-                if (symbol.isInternal() || symbol.isThis()) {
+
+            final Iterator<Symbol> symbols = block.symbolIterator();
+
+            while (symbols.hasNext()) {
+                final Symbol symbol = symbols.next();
+
+                if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
                     continue;
                 }
 
@@ -907,9 +1031,6 @@
                 }
             }
 
-            /* Correct slot numbering again */
-            frame.realign();
-
             // we may have locals that need to be initialized
             initSymbols(locals);
 
@@ -931,7 +1052,7 @@
                 @Override
                 protected void loadScope(MethodEmitter m) {
                     if(function.needsParentScope()) {
-                        m.loadScope();
+                        m.loadCompilerConstant(SCOPE);
                     } else {
                         m.loadNull();
                     }
@@ -940,118 +1061,102 @@
             foc.makeObject(method);
 
             // runScript(): merge scope into global
-            if (isFunctionNode && function.isProgram()) {
+            if (isFunctionBody && function.isProgram()) {
                 method.invoke(ScriptRuntime.MERGE_SCOPE);
             }
 
-            method.storeScope();
+            method.storeCompilerConstant(SCOPE);
         } else {
             // Since we don't have a scope, parameters didn't get assigned array indices by the FieldObjectCreator, so
             // we need to assign them separately here.
             int nextParam = 0;
-            if (isFunctionNode && function.isVarArg()) {
+            if (isFunctionBody && function.isVarArg()) {
                 for (final IdentNode param : function.getParameters()) {
                     param.getSymbol().setFieldIndex(nextParam++);
                 }
             }
+
+            final Iterator<Symbol> iter = block.symbolIterator();
+            final List<Symbol> symbols = new ArrayList<>();
+            while (iter.hasNext()) {
+                symbols.add(iter.next());
+            }
             initSymbols(symbols);
         }
 
         // Debugging: print symbols? @see --print-symbols flag
-        printSymbols(block, (isFunctionNode ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName()));
+        printSymbols(block, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName()));
     }
 
     private void initArguments(final FunctionNode function) {
-        method.loadVarArgs();
+        method.loadCompilerConstant(VARARGS);
         if(function.needsCallee()) {
-            method.loadCallee();
+            method.loadCompilerConstant(CALLEE);
         } else {
             // If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the
             // caller.
-            assert function.isStrictMode();
+            assert function.isStrict();
             method.loadNull();
         }
         method.load(function.getParameters().size());
         globalAllocateArguments();
-        method.storeArguments();
+        method.storeCompilerConstant(ARGUMENTS);
     }
 
     private void initParentScope() {
-        method.loadCallee();
+        method.loadCompilerConstant(CALLEE);
         method.invoke(ScriptFunction.GET_SCOPE);
-        method.storeScope();
+        method.storeCompilerConstant(SCOPE);
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        final boolean isCallee = functionNodeIsCallee;
-        functionNodeIsCallee = false;
-
-        if (functionNode.testResolved()) {
-            return null;
-        }
-
-        if(!(isCallee || functionNode == compiler.getFunctionNode())) {
-            newFunctionObject(functionNode);
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        if (functionNode.isLazy()) {
+            // Must do it now; can't postpone it until leaveFunctionNode()
+            newFunctionObject(functionNode, functionNode);
+            return false;
         }
 
-        if (functionNode.isLazy()) {
-            return null;
-        }
-
-        LOG.info("=== BEGIN " + functionNode.getName());
-        lexicalContext.push(functionNode);
-
-        setCurrentCompileUnit(functionNode.getCompileUnit());
-        assert getCurrentCompileUnit() != null;
-
-        setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode));
-        functionNode.setMethodEmitter(method);
+        LOG.info("=== BEGIN ", functionNode.getName());
+
+        assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
+        push(functionNode.getCompileUnit());
+        assert !compileUnits.isEmpty();
+
+        pushMethodEmitter(unit.getClassEmitter().method(functionNode));
         // Mark end for variable tables.
         method.begin();
-        method.label(functionNode.getEntryLabel());
-
-        initLocals(functionNode);
-        functionNode.setState(CompilationState.EMITTED);
-
-        return functionNode;
+
+        return true;
     }
 
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
-        // Mark end for variable tables.
-        method.label(functionNode.getBreakLabel());
-
-        if (!functionNode.needsScope()) {
-            method.markerVariable(LEAF.tag(), functionNode.getEntryLabel(), functionNode.getBreakLabel());
-        }
-
-        symbolInfo(functionNode);
         try {
             method.end(); // wrap up this method
+            pop(functionNode.getCompileUnit());
+            popMethodEmitter(method);
+            LOG.info("=== END ", functionNode.getName());
+
+            final FunctionNode newFunctionNode = functionNode.setState(getLexicalContext(), CompilationState.EMITTED);
+
+            newFunctionObject(newFunctionNode, functionNode);
+            return newFunctionNode;
         } catch (final Throwable t) {
             Context.printStackTrace(t);
             final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName());
             e.initCause(t);
             throw e;
         }
-
-        lexicalContext.pop(functionNode);
-        LOG.info("=== END " + functionNode.getName());
-        return functionNode;
     }
 
     @Override
-    public Node enterIdentNode(final IdentNode identNode) {
-        return null;
+    public boolean enterIdentNode(final IdentNode identNode) {
+        return false;
     }
 
     @Override
-    public Node enterIfNode(final IfNode ifNode) {
-        if (ifNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterIfNode(final IfNode ifNode) {
         final Node  test = ifNode.getTest();
         final Block pass = ifNode.getPass();
         final Block fail = ifNode.getFail();
@@ -1082,30 +1187,21 @@
             method.label(afterLabel);
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterIndexNode(final IndexNode indexNode) {
-        if (indexNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterIndexNode(final IndexNode indexNode) {
         load(indexNode);
-
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        if (lineNumberNode.testResolved()) {
-            return null;
-        }
-
-        final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")");
+    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
+        final Label label = new Label((String)null);
         method.label(label);
         method.lineNumber(lineNumberNode.getLineNumber(), label);
-        return null;
+        return false;
     }
 
     /**
@@ -1131,43 +1227,43 @@
         final Type elementType = arrayType.getElementType();
 
         if (units != null) {
-            final CompileUnit   savedCompileUnit = getCurrentCompileUnit();
-            final MethodEmitter savedMethod      = getCurrentMethodEmitter();
-
-            try {
-                for (final ArrayUnit unit : units) {
-                    setCurrentCompileUnit(unit.getCompileUnit());
-
-                    final String className = getCurrentCompileUnit().getUnitClassName();
-                    final String name      = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag());
-                    final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
-
-                    setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
-                    method.setFunctionNode(getCurrentFunctionNode());
-                    method.begin();
-
-                    fixScopeSlot();
-
-                    method.load(arrayType, SPLIT_ARRAY_ARG.slot());
-
-                    for (int i = unit.getLo(); i < unit.getHi(); i++) {
-                        storeElement(nodes, elementType, postsets[i]);
-                    }
-
-                    method._return();
-                    method.end();
-
-                    savedMethod.loadThis();
-                    savedMethod.swap();
-                    savedMethod.loadCallee();
-                    savedMethod.swap();
-                    savedMethod.loadScope();
-                    savedMethod.swap();
-                    savedMethod.invokestatic(className, name, signature);
+            final MethodEmitter savedMethod = method;
+
+            for (final ArrayUnit arrayUnit : units) {
+                push(arrayUnit.getCompileUnit());
+
+                final String className = unit.getUnitClassName();
+                final String name      = getLexicalContext().getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName());
+                final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
+
+                final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature);
+                pushMethodEmitter(me);
+
+                method.setFunctionNode(getLexicalContext().getCurrentFunction());
+                method.begin();
+
+                fixScopeSlot();
+
+                method.load(arrayType, SPLIT_ARRAY_ARG.slot());
+
+                for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
+                    storeElement(nodes, elementType, postsets[i]);
                 }
-            } finally {
-                setCurrentCompileUnit(savedCompileUnit);
-                setCurrentMethodEmitter(savedMethod);
+
+                method._return();
+                method.end();
+                popMethodEmitter(me);
+
+                assert method == savedMethod;
+                method.loadCompilerConstant(THIS);
+                method.swap();
+                method.loadCompilerConstant(CALLEE);
+                method.swap();
+                method.loadCompilerConstant(SCOPE);
+                method.swap();
+                method.invokestatic(className, name, signature);
+
+                pop(unit);
             }
 
             return method;
@@ -1217,12 +1313,12 @@
      * @param string string to load
      */
     void loadConstant(final String string) {
-        final String       unitClassName = getCurrentCompileUnit().getUnitClassName();
-        final ClassEmitter classEmitter  = getCurrentCompileUnit().getClassEmitter();
+        final String       unitClassName = unit.getUnitClassName();
+        final ClassEmitter classEmitter  = unit.getClassEmitter();
         final int          index         = compiler.getConstantData().add(string);
 
         method.load(index);
-        method.invokestatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class));
+        method.invokestatic(unitClassName, GET_STRING.symbolName(), methodDescriptor(String.class, int.class));
         classEmitter.needGetConstantMethod(String.class);
     }
 
@@ -1233,14 +1329,14 @@
      * @param object object to load
      */
     void loadConstant(final Object object) {
-        final String       unitClassName = getCurrentCompileUnit().getUnitClassName();
-        final ClassEmitter classEmitter  = getCurrentCompileUnit().getClassEmitter();
+        final String       unitClassName = unit.getUnitClassName();
+        final ClassEmitter classEmitter  = unit.getClassEmitter();
         final int          index         = compiler.getConstantData().add(object);
         final Class<?>     cls           = object.getClass();
 
         if (cls == PropertyMap.class) {
             method.load(index);
-            method.invokestatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class));
+            method.invokestatic(unitClassName, GET_MAP.symbolName(), methodDescriptor(PropertyMap.class, int.class));
             classEmitter.needGetConstantMethod(PropertyMap.class);
         } else if (cls.isArray()) {
             method.load(index);
@@ -1303,14 +1399,14 @@
             return loadRegexToken(regexToken);
         }
         // emit field
-        final String       regexName    = getCurrentFunctionNode().uniqueName(REGEX_PREFIX.tag());
-        final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter();
+        final String       regexName    = getLexicalContext().getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName());
+        final ClassEmitter classEmitter = unit.getClassEmitter();
 
         classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class);
         regexFieldCount++;
 
         // get field, if null create new regex, finally clone regex object
-        method.getStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class));
+        method.getStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class));
         method.dup();
         final Label cachedLabel = new Label("cached");
         method.ifnonnull(cachedLabel);
@@ -1318,7 +1414,7 @@
         method.pop();
         loadRegexToken(regexToken);
         method.dup();
-        method.putStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class));
+        method.putStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class));
 
         method.label(cachedLabel);
         globalRegExpCopy();
@@ -1328,18 +1424,14 @@
 
     @SuppressWarnings("rawtypes")
     @Override
-    public Node enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         assert literalNode.getSymbol() != null : literalNode + " has no symbol";
         load(literalNode).store(literalNode.getSymbol());
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterObjectNode(final ObjectNode objectNode) {
-        if (objectNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterObjectNode(final ObjectNode objectNode) {
         final List<Node> elements = objectNode.getElements();
         final int        size     = elements.size();
 
@@ -1404,14 +1496,14 @@
 
         if (!hasGettersSetters) {
             method.store(objectNode.getSymbol());
-            return null;
+            return false;
         }
 
         for (final Node element : elements) {
             final PropertyNode propertyNode = (PropertyNode)element;
             final Object       key          = propertyNode.getKey();
-            final FunctionNode getter       = (FunctionNode)propertyNode.getGetter();
-            final FunctionNode setter       = (FunctionNode)propertyNode.getSetter();
+            final FunctionNode getter       = propertyNode.getGetter();
+            final FunctionNode setter       = propertyNode.getSetter();
 
             if (getter == null && setter == null) {
                 continue;
@@ -1436,35 +1528,25 @@
 
         method.store(objectNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterReturnNode(final ReturnNode returnNode) {
-        if (returnNode.testResolved()) {
-            return null;
-        }
-
-        // Set the split return flag in the scope if this is a split method fragment.
-        if (method.getSplitNode() != null) {
-            assert method.getSplitNode().hasReturn() : "unexpected return in split node";
-
-            method.loadScope();
-            method.checkcast(Scope.class);
-            method.load(0);
-            method.invoke(Scope.SET_SPLIT_STATE);
-        }
+    public boolean enterReturnNode(final ReturnNode returnNode) {
+        method.registerReturn();
+
+        final Type returnType = getLexicalContext().getCurrentFunction().getReturnType();
 
         final Node expression = returnNode.getExpression();
         if (expression != null) {
             load(expression);
         } else {
-            method.loadUndefined(getCurrentFunctionNode().getReturnType());
+            method.loadUndefined(returnType);
         }
 
-        method._return(getCurrentFunctionNode().getReturnType());
-
-        return null;
+        method._return(returnType);
+
+        return false;
     }
 
     private static boolean isNullLiteral(final Node node) {
@@ -1542,19 +1624,20 @@
         }
 
         assert args.size() == 2;
-        final Node lhs = args.get(0);
-        final Node rhs = args.get(1);
-
         final Type returnType = node.getType();
-        load(lhs);
-        load(rhs);
+
+        load(args.get(0));
+        load(args.get(1));
 
         Request finalRequest = request;
 
+        //if the request is a comparison, i.e. one that can be reversed
+        //it keeps its semantic, but make sure that the object comes in
+        //last
         final Request reverse = Request.reverse(request);
-        if (method.peekType().isObject() && reverse != null) {
-            if (!method.peekType(1).isObject()) {
-                method.swap();
+        if (method.peekType().isObject() && reverse != null) { //rhs is object
+            if (!method.peekType(1).isObject()) { //lhs is not object
+                method.swap(); //prefer object as lhs
                 finalRequest = reverse;
             }
         }
@@ -1581,11 +1664,7 @@
     }
 
     @Override
-    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
-        if (runtimeNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
         /*
          * First check if this should be something other than a runtime node
          * AccessSpecializer might have changed the type
@@ -1624,7 +1703,7 @@
                 method.add();
                 method.convert(type);
                 method.store(symbol);
-                return null;
+                return false;
             default:
                 // it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar
                 // assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state";
@@ -1636,11 +1715,11 @@
         final List<Node> args = runtimeNode.getArgs();
 
         if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
-            return null;
+            return false;
         }
 
         if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) {
-            return null;
+            return false;
         }
 
         for (final Node arg : runtimeNode.getArgs()) {
@@ -1658,129 +1737,146 @@
         method.convert(runtimeNode.getType());
         method.store(runtimeNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSplitNode(final SplitNode splitNode) {
-        if (splitNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterSplitNode(final SplitNode splitNode) {
         final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
 
-        final FunctionNode fn   = getCurrentFunctionNode();
+        final FunctionNode fn   = getLexicalContext().getCurrentFunction();
         final String className  = splitCompileUnit.getUnitClassName();
         final String name       = splitNode.getName();
 
-        final Class<?>   rtype  = fn.getReturnType().getTypeClass();
-        final boolean needsArguments = fn.needsArguments();
-        final Class<?>[] ptypes = needsArguments ?
+        final Class<?>   rtype          = fn.getReturnType().getTypeClass();
+        final boolean    needsArguments = fn.needsArguments();
+        final Class<?>[] ptypes         = needsArguments ?
                 new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, Object.class} :
                 new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class};
 
-        setCurrentCompileUnit(splitCompileUnit);
-        splitNode.setCompileUnit(splitCompileUnit);
+        final MethodEmitter caller = method;
+        push(splitCompileUnit);
 
         final Call splitCall = staticCallNoLookup(
             className,
             name,
             methodDescriptor(rtype, ptypes));
 
-        setCurrentMethodEmitter(
-            splitCompileUnit.getClassEmitter().method(
-                EnumSet.of(Flag.PUBLIC, Flag.STATIC),
-                name,
-                rtype,
-                ptypes));
+        final MethodEmitter splitEmitter =
+                splitCompileUnit.getClassEmitter().method(
+                        splitNode,
+                        name,
+                        rtype,
+                        ptypes);
+
+        pushMethodEmitter(splitEmitter);
 
         method.setFunctionNode(fn);
-        method.setSplitNode(splitNode);
-        splitNode.setMethodEmitter(method);
-
-        final MethodEmitter caller = splitNode.getCaller();
-        if(fn.needsCallee()) {
-            caller.loadCallee();
+
+        if (fn.needsCallee()) {
+            caller.loadCompilerConstant(CALLEE);
         } else {
             caller.loadNull();
         }
-        caller.loadThis();
-        caller.loadScope();
+        caller.loadCompilerConstant(THIS);
+        caller.loadCompilerConstant(SCOPE);
         if (needsArguments) {
-            caller.loadArguments();
+            caller.loadCompilerConstant(ARGUMENTS);
         }
         caller.invoke(splitCall);
-        caller.storeResult();
+        caller.storeCompilerConstant(RETURN);
 
         method.begin();
 
         method.loadUndefined(fn.getReturnType());
-        method.storeResult();
+        method.storeCompilerConstant(RETURN);
 
         fixScopeSlot();
 
-        return splitNode;
+        return true;
     }
 
     private void fixScopeSlot() {
-        if (getCurrentFunctionNode().getScopeNode().getSymbol().getSlot() != SCOPE.slot()) {
+        if (getLexicalContext().getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) {
             // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method)
             method.load(Type.typeFor(ScriptObject.class), SCOPE.slot());
-            method.storeScope();
+            method.storeCompilerConstant(SCOPE);
         }
     }
 
     @Override
     public Node leaveSplitNode(final SplitNode splitNode) {
+        assert method instanceof SplitMethodEmitter;
+        final boolean     hasReturn = method.hasReturn();
+        final List<Label> targets   = method.getExternalTargets();
+
         try {
             // Wrap up this method.
-            method.loadResult();
-            method._return(getCurrentFunctionNode().getReturnType());
+
+            method.loadCompilerConstant(RETURN);
+            method._return(getLexicalContext().getCurrentFunction().getReturnType());
             method.end();
+
+            pop(splitNode.getCompileUnit());
+            popMethodEmitter(method);
+
         } catch (final Throwable t) {
             Context.printStackTrace(t);
-            final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentFunctionNode().getSource().getName());
+            final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getLexicalContext().getCurrentFunction().getSource().getName());
             e.initCause(t);
             throw e;
         }
 
         // Handle return from split method if there was one.
-        final MethodEmitter caller      = splitNode.getCaller();
-        final List<Label>   targets     = splitNode.getExternalTargets();
-        final int           targetCount = targets.size();
-
-        if (splitNode.hasReturn() || targetCount > 0) {
-
-            caller.loadScope();
-            caller.checkcast(Scope.class);
-            caller.invoke(Scope.GET_SPLIT_STATE);
-
-            // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue
-            final Label   breakLabel = new Label("no_split_state");
-            final int     low        = splitNode.hasReturn() ? 0 : 1;
-            final int     labelCount = targetCount + 1 - low;
-            final Label[] labels     = new Label[labelCount];
+        final MethodEmitter caller = method;
+        final int     targetCount = targets.size();
+
+        //no external jump targets or return in switch node
+        if (!hasReturn && targets.isEmpty()) {
+            return splitNode;
+        }
+
+        caller.loadCompilerConstant(SCOPE);
+        caller.checkcast(Scope.class);
+        caller.invoke(Scope.GET_SPLIT_STATE);
+
+        final Label breakLabel = new Label("no_split_state");
+        // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue
+
+        //the common case is that we don't need a switch
+        if (targetCount == 0) {
+            assert hasReturn;
+            caller.ifne(breakLabel);
+            //has to be zero
+            caller.label(new Label("split_return"));
+            method.loadCompilerConstant(RETURN);
+            caller._return(getLexicalContext().getCurrentFunction().getReturnType());
+            caller.label(breakLabel);
+        } else {
+            assert !targets.isEmpty();
+
+            final int     low         = hasReturn ? 0 : 1;
+            final int     labelCount  = targetCount + 1 - low;
+            final Label[] labels      = new Label[labelCount];
 
             for (int i = 0; i < labelCount; i++) {
-                labels[i] = new Label("split_state_" + i);
+                labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1));
             }
-
             caller.tableswitch(low, targetCount, breakLabel, labels);
             for (int i = low; i <= targetCount; i++) {
                 caller.label(labels[i - low]);
                 if (i == 0) {
-                    caller.loadResult();
-                    caller._return(getCurrentFunctionNode().getReturnType());
+                    caller.loadCompilerConstant(RETURN);
+                    caller._return(getLexicalContext().getCurrentFunction().getReturnType());
                 } else {
                     // Clear split state.
-                    caller.loadScope();
+                    caller.loadCompilerConstant(SCOPE);
                     caller.checkcast(Scope.class);
                     caller.load(-1);
                     caller.invoke(Scope.SET_SPLIT_STATE);
-                    caller.splitAwareGoto(targets.get(i - 1));
+                    caller.splitAwareGoto(getLexicalContext(), targets.get(i - 1));
                 }
             }
-
             caller.label(breakLabel);
         }
 
@@ -1788,11 +1884,7 @@
     }
 
     @Override
-    public Node enterSwitchNode(final SwitchNode switchNode) {
-        if (switchNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterSwitchNode(final SwitchNode switchNode) {
         final Node           expression  = switchNode.getExpression();
         final Symbol         tag         = switchNode.getTag();
         final boolean        allInteger  = tag.getSymbolType().isInteger();
@@ -1810,7 +1902,7 @@
 
         if (cases.isEmpty()) {
             method.label(breakLabel);
-            return null;
+            return false;
         }
 
         if (allInteger) {
@@ -1916,15 +2008,11 @@
             method.label(breakLabel);
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterThrowNode(final ThrowNode throwNode) {
-        if (throwNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterThrowNode(final ThrowNode throwNode) {
         method._new(ECMAException.class).dup();
 
         final Node   expression = throwNode.getExpression();
@@ -1943,15 +2031,11 @@
 
         method.athrow();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterTryNode(final TryNode tryNode) {
-        if (tryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterTryNode(final TryNode tryNode) {
         final Block       body        = tryNode.getBody();
         final List<Block> catchBlocks = tryNode.getCatchBlocks();
         final Symbol      symbol      = tryNode.getException();
@@ -1974,74 +2058,68 @@
         method.store(symbol);
 
         for (int i = 0; i < catchBlocks.size(); i++) {
-            final Block saveBlock = getCurrentBlock();
             final Block catchBlock = catchBlocks.get(i);
 
-            setCurrentBlock(catchBlock);
-
-            try {
-                enterBlock(catchBlock);
-
-                final CatchNode catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
-                final IdentNode exception          = catchNode.getException();
-                final Node      exceptionCondition = catchNode.getExceptionCondition();
-                final Block     catchBody          = catchNode.getBody();
-
-                if (catchNode.isSyntheticRethrow()) {
-                    // Generate catch body (inlined finally) and rethrow exception
-                    catchBody.accept(this);
-                    method.load(symbol).athrow();
-                    lexicalContext.pop(catchBlock);
-                    continue;
+            //TODO this is very ugly - try not to call enter/leave methods directly
+            //better to use the implicit lexical context scoping given by the visitor's
+            //accept method.
+            getLexicalContext().push(catchBlock);
+            enterBlock(catchBlock);
+
+            final CatchNode catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
+            final IdentNode exception          = catchNode.getException();
+            final Node      exceptionCondition = catchNode.getExceptionCondition();
+            final Block     catchBody          = catchNode.getBody();
+
+            new Store<IdentNode>(exception) {
+                @Override
+                protected void storeNonDiscard() {
+                    return;
                 }
-
-                new Store<IdentNode>(exception) {
-                    @Override
-                    protected void evaluate() {
-                        /*
-                         * If caught object is an instance of ECMAException, then
-                         * bind obj.thrown to the script catch var. Or else bind the
-                         * caught object itself to the script catch var.
-                         */
-                        final Label notEcmaException = new Label("no_ecma_exception");
-
-                        method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException);
-                        method.checkcast(ECMAException.class); //TODO is this necessary?
-                        method.getField(ECMAException.THROWN);
-                        method.label(notEcmaException);
-                    }
-                }.store();
-
-                final Label next;
-
-                if (exceptionCondition != null) {
-                    next = new Label("next");
-                    load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next);
+                @Override
+                protected void evaluate() {
+                    /*
+                     * If caught object is an instance of ECMAException, then
+                     * bind obj.thrown to the script catch var. Or else bind the
+                     * caught object itself to the script catch var.
+                     */
+                    final Label notEcmaException = new Label("no_ecma_exception");
+
+                    method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException);
+                    method.checkcast(ECMAException.class); //TODO is this necessary?
+                    method.getField(ECMAException.THROWN);
+                    method.label(notEcmaException);
+                }
+            }.store();
+
+            final Label next;
+
+            if (exceptionCondition != null) {
+                next = new Label("next");
+                load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next);
+            } else {
+                next = null;
+            }
+
+            catchBody.accept(this);
+
+            if (i + 1 != catchBlocks.size() && !catchBody.hasTerminalFlags()) {
+                method._goto(skip);
+            }
+
+            if (next != null) {
+                if (i + 1 == catchBlocks.size()) {
+                    // no next catch block - rethrow if condition failed
+                    method._goto(skip);
+                    method.label(next);
+                    method.load(symbol).athrow();
                 } else {
-                    next = null;
-                }
-
-                catchBody.accept(this);
-
-                if (i + 1 != catchBlocks.size() && !catchBody.hasTerminalFlags()) {
-                    method._goto(skip);
+                    method.label(next);
                 }
-
-                if (next != null) {
-                    if (i + 1 == catchBlocks.size()) {
-                        // no next catch block - rethrow if condition failed
-                        method._goto(skip);
-                        method.label(next);
-                        method.load(symbol).athrow();
-                    } else {
-                        method.label(next);
-                    }
-                }
-
-                leaveBlock(catchBlock);
-            } finally {
-                setCurrentBlock(saveBlock);
             }
+
+            leaveBlock(catchBlock);
+            getLexicalContext().pop(catchBlock);
         }
 
         method.label(skip);
@@ -2049,15 +2127,15 @@
 
         // Finally body is always inlined elsewhere so it doesn't need to be emitted
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterVarNode(final VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         final Node init = varNode.getInit();
 
-        if (varNode.testResolved() || init == null) {
-            return null;
+        if (init == null) {
+            return false;
         }
 
         final Symbol varSymbol = varNode.getSymbol();
@@ -2067,7 +2145,7 @@
 
         final boolean needsScope = varSymbol.isScope();
         if (needsScope) {
-            method.loadScope();
+            method.loadCompilerConstant(SCOPE);
         }
         load(init);
 
@@ -2087,22 +2165,18 @@
             method.store(varSymbol);
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterWhileNode(final WhileNode whileNode) {
-        if (whileNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterWhileNode(final WhileNode whileNode) {
         final Node  test          = whileNode.getTest();
         final Block body          = whileNode.getBody();
         final Label breakLabel    = whileNode.getBreakLabel();
         final Label continueLabel = whileNode.getContinueLabel();
         final Label loopLabel     = new Label("loop");
 
-        if (!(whileNode instanceof DoWhileNode)) {
+        if (!whileNode.isDoWhile()) {
             method._goto(continueLabel);
         }
 
@@ -2114,90 +2188,95 @@
             method.label(breakLabel);
         }
 
-        return null;
+        return false;
     }
 
     private void closeWith() {
-        method.loadScope();
-        method.invoke(ScriptRuntime.CLOSE_WITH);
-        method.storeScope();
+        if(method.hasScope()) {
+            method.loadCompilerConstant(SCOPE);
+            method.invoke(ScriptRuntime.CLOSE_WITH);
+            method.storeCompilerConstant(SCOPE);
+        }
     }
 
     @Override
-    public Node enterWithNode(final WithNode withNode) {
-        if (withNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterWithNode(final WithNode withNode) {
         final Node expression = withNode.getExpression();
         final Node body       = withNode.getBody();
 
-        final Label tryLabel   = new Label("with_try");
-        final Label endLabel   = new Label("with_end");
-        final Label catchLabel = new Label("with_catch");
-        final Label exitLabel  = new Label("with_exit");
-
-        method.label(tryLabel);
-
-        method.loadScope();
+        // It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's
+        // pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the
+        // scope object, its' possible that it won't have a slot assigned. In this case we'll only evaluate expression
+        // for its side effect and visit the body, and not bother opening and closing a WithObject.
+        final boolean hasScope = method.hasScope();
+
+        final Label tryLabel;
+        if(hasScope) {
+            tryLabel = new Label("with_try");
+            method.label(tryLabel);
+            method.loadCompilerConstant(SCOPE);
+        } else {
+            tryLabel = null;
+        }
+
         load(expression);
-
         assert expression.getType().isObject() : "with expression needs to be object: " + expression;
 
-        method.invoke(ScriptRuntime.OPEN_WITH);
-        method.storeScope();
-
+        if(hasScope) {
+            // Construct a WithObject if we have a scope
+            method.invoke(ScriptRuntime.OPEN_WITH);
+            method.storeCompilerConstant(SCOPE);
+        } else {
+            // We just loaded the expression for its side effect; discard it
+            method.pop();
+        }
+
+
+        // Always process body
         body.accept(this);
 
-        if (!body.isTerminal()) {
+        if(hasScope) {
+            // Ensure we always close the WithObject
+            final Label endLabel   = new Label("with_end");
+            final Label catchLabel = new Label("with_catch");
+            final Label exitLabel  = new Label("with_exit");
+
+            if (!body.isTerminal()) {
+                closeWith();
+                method._goto(exitLabel);
+            }
+
+            method.label(endLabel);
+
+            method._catch(catchLabel);
             closeWith();
-            method._goto(exitLabel);
+            method.athrow();
+
+            method.label(exitLabel);
+
+            method._try(tryLabel, endLabel, catchLabel);
         }
-
-        method.label(endLabel);
-
-        method._catch(catchLabel);
-        closeWith();
-        method.athrow();
-
-        method.label(exitLabel);
-
-        method._try(tryLabel, endLabel, catchLabel);
-
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterADD(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterADD(final UnaryNode unaryNode) {
         load(unaryNode.rhs());
         assert unaryNode.rhs().getType().isNumber();
         method.store(unaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterBIT_NOT(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterBIT_NOT(final UnaryNode unaryNode) {
         load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol());
-
-        return null;
+        return false;
     }
 
     // do this better with convert calls to method. TODO
     @Override
-    public Node enterCONVERT(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterCONVERT(final UnaryNode unaryNode) {
         final Node rhs = unaryNode.rhs();
         final Type to  = unaryNode.getType();
 
@@ -2230,15 +2309,11 @@
 
         method.store(unaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterDECINC(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterDECINC(final UnaryNode unaryNode) {
         final Node      rhs         = unaryNode.rhs();
         final Type      type        = unaryNode.getType();
         final TokenType tokenType   = unaryNode.tokenType();
@@ -2282,32 +2357,28 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterDISCARD(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterDISCARD(final UnaryNode unaryNode) {
         final Node rhs = unaryNode.rhs();
 
+       // System.err.println("**** Enter discard " + unaryNode);
+        discard.push(rhs);
         load(rhs);
 
-        if (rhs.shouldDiscard()) {
+        if (discard.peek() == rhs) {
+            assert !rhs.isAssignment();
             method.pop();
+            discard.pop();
         }
-
-        return null;
+       // System.err.println("**** Leave discard " + unaryNode);
+        return false;
     }
 
     @Override
-    public Node enterNEW(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterNEW(final UnaryNode unaryNode) {
         final CallNode callNode = (CallNode)unaryNode.rhs();
         final List<Node> args   = callNode.getArgs();
 
@@ -2317,15 +2388,11 @@
         method.dynamicNew(1 + loadArgs(args), getCallSiteFlags());
         method.store(unaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterNOT(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterNOT(final UnaryNode unaryNode) {
         final Node rhs = unaryNode.rhs();
 
         load(rhs);
@@ -2342,18 +2409,14 @@
         method.label(afterLabel);
         method.store(unaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSUB(final UnaryNode unaryNode) {
-        if (unaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterSUB(final UnaryNode unaryNode) {
         load(unaryNode.rhs()).neg().store(unaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) {
@@ -2366,11 +2429,7 @@
     }
 
     @Override
-    public Node enterADD(final BinaryNode binaryNode) {
-        if (binaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterADD(final BinaryNode binaryNode) {
         final Node lhs = binaryNode.lhs();
         final Node rhs = binaryNode.rhs();
 
@@ -2384,14 +2443,10 @@
             method.store(binaryNode.getSymbol());
         }
 
-        return null;
+        return false;
     }
 
-    private Node enterAND_OR(final BinaryNode binaryNode) {
-        if (binaryNode.testResolved()) {
-            return null;
-        }
-
+    private boolean enterAND_OR(final BinaryNode binaryNode) {
         final Node lhs = binaryNode.lhs();
         final Node rhs = binaryNode.rhs();
 
@@ -2410,20 +2465,16 @@
         method.label(skip);
         method.store(binaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterAND(final BinaryNode binaryNode) {
+    public boolean enterAND(final BinaryNode binaryNode) {
         return enterAND_OR(binaryNode);
     }
 
     @Override
-    public Node enterASSIGN(final BinaryNode binaryNode) {
-        if (binaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterASSIGN(final BinaryNode binaryNode) {
         final Node lhs = binaryNode.lhs();
         final Node rhs = binaryNode.rhs();
 
@@ -2442,7 +2493,7 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     /**
@@ -2473,14 +2524,6 @@
             this.opType = opType;
         }
 
-        @Override
-        public void store() {
-            if (assignNode.testResolved()) {
-                return;
-            }
-            super.store();
-        }
-
         protected abstract void op();
 
         @Override
@@ -2493,35 +2536,43 @@
     }
 
     @Override
-    public Node enterASSIGN_ADD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_ADD(final BinaryNode binaryNode) {
         assert RuntimeNode.Request.ADD.canSpecialize();
+        final Type lhsType = binaryNode.lhs().getType();
+        final Type rhsType = binaryNode.rhs().getType();
         final boolean specialize = binaryNode.getType() == Type.OBJECT;
 
         new AssignOp(binaryNode) {
-            @Override
-            protected boolean isSelfModifying() {
-                return !specialize;
-            }
 
             @Override
             protected void op() {
-                method.add();
+                if (specialize) {
+                    method.dynamicRuntimeCall(
+                            new SpecializedRuntimeNode(
+                                Request.ADD,
+                                new Type[] {
+                                    lhsType,
+                                    rhsType,
+                                },
+                                Type.OBJECT).getInitialName(),
+                            Type.OBJECT,
+                            Request.ADD);
+                } else {
+                    method.add();
+                }
             }
 
             @Override
             protected void evaluate() {
-                if (specialize && specializationCheck(Request.ADD, assignNode, Arrays.asList(assignNode.lhs(), assignNode.rhs()))) {
-                    return;
-                }
                 super.evaluate();
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
@@ -2529,11 +2580,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
@@ -2541,11 +2592,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
@@ -2553,11 +2604,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_DIV(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_DIV(final BinaryNode binaryNode) {
         new AssignOp(binaryNode) {
             @Override
             protected void op() {
@@ -2565,11 +2616,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_MOD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MOD(final BinaryNode binaryNode) {
         new AssignOp(binaryNode) {
             @Override
             protected void op() {
@@ -2577,11 +2628,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_MUL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MUL(final BinaryNode binaryNode) {
         new AssignOp(binaryNode) {
             @Override
             protected void op() {
@@ -2589,11 +2640,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_SAR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SAR(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
@@ -2601,11 +2652,11 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_SHL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHL(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
@@ -2613,24 +2664,24 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_SHR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHR(final BinaryNode binaryNode) {
         new AssignOp(Type.INT, binaryNode) {
             @Override
             protected void op() {
                 method.shr();
-                method.convert(Type.LONG).load(0xffff_ffffL).and();
+                method.convert(Type.LONG).load(JSType.MAX_UINT).and();
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterASSIGN_SUB(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SUB(final BinaryNode binaryNode) {
         new AssignOp(binaryNode) {
             @Override
             protected void op() {
@@ -2638,7 +2689,7 @@
             }
         }.store();
 
-        return null;
+        return false;
     }
 
     /**
@@ -2649,9 +2700,6 @@
         protected abstract void op();
 
         protected void evaluate(final BinaryNode node) {
-            if (node.testResolved()) {
-                return;
-            }
             load(node.lhs());
             load(node.rhs());
             op();
@@ -2660,7 +2708,7 @@
     }
 
     @Override
-    public Node enterBIT_AND(final BinaryNode binaryNode) {
+    public boolean enterBIT_AND(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2668,11 +2716,11 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterBIT_OR(final BinaryNode binaryNode) {
+    public boolean enterBIT_OR(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2680,11 +2728,11 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterBIT_XOR(final BinaryNode binaryNode) {
+    public boolean enterBIT_XOR(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2692,14 +2740,10 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
-    private Node enterComma(final BinaryNode binaryNode) {
-        if (binaryNode.testResolved()) {
-            return null;
-        }
-
+    private boolean enterComma(final BinaryNode binaryNode) {
         final Node lhs = binaryNode.lhs();
         final Node rhs = binaryNode.rhs();
 
@@ -2707,21 +2751,21 @@
         load(rhs);
         method.store(binaryNode.getSymbol());
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterCOMMARIGHT(final BinaryNode binaryNode) {
+    public boolean enterCOMMARIGHT(final BinaryNode binaryNode) {
         return enterComma(binaryNode);
     }
 
     @Override
-    public Node enterCOMMALEFT(final BinaryNode binaryNode) {
+    public boolean enterCOMMALEFT(final BinaryNode binaryNode) {
         return enterComma(binaryNode);
     }
 
     @Override
-    public Node enterDIV(final BinaryNode binaryNode) {
+    public boolean enterDIV(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2729,10 +2773,10 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
-    private Node enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) {
+    private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) {
         final Type lhsType = lhs.getType();
         final Type rhsType = rhs.getType();
 
@@ -2758,48 +2802,45 @@
         method.convert(type);
         method.store(symbol);
 
-        return null;
+        return false;
     }
 
-    private Node enterCmp(final BinaryNode binaryNode, final Condition cond) {
-        if (binaryNode.testResolved()) {
-            return null;
-        }
+    private boolean enterCmp(final BinaryNode binaryNode, final Condition cond) {
         return enterCmp(binaryNode.lhs(), binaryNode.rhs(), cond, binaryNode.getType(), binaryNode.getSymbol());
     }
 
     @Override
-    public Node enterEQ(final BinaryNode binaryNode) {
+    public boolean enterEQ(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.EQ);
     }
 
     @Override
-    public Node enterEQ_STRICT(final BinaryNode binaryNode) {
+    public boolean enterEQ_STRICT(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.EQ);
     }
 
     @Override
-    public Node enterGE(final BinaryNode binaryNode) {
+    public boolean enterGE(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.GE);
     }
 
     @Override
-    public Node enterGT(final BinaryNode binaryNode) {
+    public boolean enterGT(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.GT);
     }
 
     @Override
-    public Node enterLE(final BinaryNode binaryNode) {
+    public boolean enterLE(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.LE);
     }
 
     @Override
-    public Node enterLT(final BinaryNode binaryNode) {
+    public boolean enterLT(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.LT);
     }
 
     @Override
-    public Node enterMOD(final BinaryNode binaryNode) {
+    public boolean enterMOD(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2807,11 +2848,11 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterMUL(final BinaryNode binaryNode) {
+    public boolean enterMUL(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2819,26 +2860,26 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterNE(final BinaryNode binaryNode) {
+    public boolean enterNE(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.NE);
     }
 
     @Override
-    public Node enterNE_STRICT(final BinaryNode binaryNode) {
+    public boolean enterNE_STRICT(final BinaryNode binaryNode) {
         return enterCmp(binaryNode, Condition.NE);
     }
 
     @Override
-    public Node enterOR(final BinaryNode binaryNode) {
+    public boolean enterOR(final BinaryNode binaryNode) {
         return enterAND_OR(binaryNode);
     }
 
     @Override
-    public Node enterSAR(final BinaryNode binaryNode) {
+    public boolean enterSAR(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2846,11 +2887,11 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSHL(final BinaryNode binaryNode) {
+    public boolean enterSHL(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2858,24 +2899,24 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSHR(final BinaryNode binaryNode) {
+    public boolean enterSHR(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
                 method.shr();
-                method.convert(Type.LONG).load(0xffff_ffffL).and();
+                method.convert(Type.LONG).load(JSType.MAX_UINT).and();
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSUB(final BinaryNode binaryNode) {
+    public boolean enterSUB(final BinaryNode binaryNode) {
         new BinaryArith() {
             @Override
             protected void op() {
@@ -2883,18 +2924,11 @@
             }
         }.evaluate(binaryNode);
 
-        return null;
+        return false;
     }
 
-    /*
-     * Ternary visits.
-     */
     @Override
-    public Node enterTernaryNode(final TernaryNode ternaryNode) {
-        if (ternaryNode.testResolved()) {
-            return null;
-        }
-
+    public boolean enterTernaryNode(final TernaryNode ternaryNode) {
         final Node lhs   = ternaryNode.lhs();
         final Node rhs   = ternaryNode.rhs();
         final Node third = ternaryNode.third();
@@ -2926,7 +2960,7 @@
         method.label(exitLabel);
         method.store(symbol);
 
-        return null;
+        return false;
     }
 
     /**
@@ -2955,7 +2989,7 @@
         if (scopeCalls.containsKey(scopeCall)) {
             return scopeCalls.get(scopeCall);
         }
-        scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall"));
+        scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall"));
         scopeCalls.put(scopeCall, scopeCall);
         return scopeCall;
     }
@@ -2974,7 +3008,7 @@
         if (scopeCalls.containsKey(scopeCall)) {
             return scopeCalls.get(scopeCall);
         }
-        scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall"));
+        scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall"));
         scopeCalls.put(scopeCall, scopeCall);
         return scopeCall;
     }
@@ -3037,9 +3071,6 @@
         /** The target node to store to, e.g. x */
         private final Node target;
 
-        /** Should the result always be discarded, no matter what? */
-        private final boolean alwaysDiscard;
-
         /** How deep on the stack do the arguments go if this generates an indy call */
         private int depth;
 
@@ -3055,7 +3086,6 @@
         protected Store(final T assignNode, final Node target) {
             this.assignNode = assignNode;
             this.target = target;
-            this.alwaysDiscard = assignNode == target;
         }
 
         /**
@@ -3077,21 +3107,21 @@
 
         private void prologue() {
             final Symbol targetSymbol = target.getSymbol();
-            final Symbol scopeSymbol  = getCurrentFunctionNode().getScopeNode().getSymbol();
+            final Symbol scopeSymbol  = getLexicalContext().getCurrentFunction().compilerConstant(SCOPE);
 
             /**
              * This loads the parts of the target, e.g base and index. they are kept
              * on the stack throughout the store and used at the end to execute it
              */
 
-            target.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
+            target.accept(new NodeVisitor() {
                 @Override
-                public Node enterIdentNode(final IdentNode node) {
+                public boolean enterIdentNode(final IdentNode node) {
                     if (targetSymbol.isScope()) {
                         method.load(scopeSymbol);
                         depth++;
                     }
-                    return null;
+                    return false;
                 }
 
                 private void enterBaseNode() {
@@ -3109,13 +3139,13 @@
                 }
 
                 @Override
-                public Node enterAccessNode(final AccessNode node) {
+                public boolean enterAccessNode(final AccessNode node) {
                     enterBaseNode();
-                    return null;
+                    return false;
                 }
 
                 @Override
-                public Node enterIndexNode(final IndexNode node) {
+                public boolean enterIndexNode(final IndexNode node) {
                     enterBaseNode();
 
                     final Node index = node.getIndex();
@@ -3131,14 +3161,14 @@
                         method.dup(1);
                     }
 
-                    return null;
+                    return false;
                 }
 
             });
         }
 
         private Symbol quickSymbol(final Type type) {
-            return quickSymbol(type, QUICK_PREFIX.tag());
+            return quickSymbol(type, QUICK_PREFIX.symbolName());
         }
 
         /**
@@ -3151,22 +3181,28 @@
          * @return the quick symbol
          */
         private Symbol quickSymbol(final Type type, final String prefix) {
-            final String name = getCurrentFunctionNode().uniqueName(prefix);
-            final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL, null, null);
+            final String name = getLexicalContext().getCurrentFunction().uniqueName(prefix);
+            final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL);
 
             symbol.setType(type);
-            symbol.setSlot(getCurrentBlock().getFrame().getSlotCount());
+            final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1];
+            nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount();
+            symbol.setSlot(quickSlot);
 
             return symbol;
         }
 
         // store the result that "lives on" after the op, e.g. "i" in i++ postfix.
         protected void storeNonDiscard() {
-            if (assignNode.shouldDiscard() || alwaysDiscard) {
-                assignNode.setDiscard(false);
+            if (discard.peek() == assignNode) {
+                assert assignNode.isAssignment();
+                discard.pop();
                 return;
             }
 
+            //System.err.println("Store with out discard that shouldn't just return " + assignNode);
+            //new Throwable().printStackTrace();
+
             final Symbol symbol = assignNode.getSymbol();
             if (symbol.hasSlot()) {
                 method.dup().store(symbol);
@@ -3191,22 +3227,22 @@
              */
             method.convert(target.getType());
 
-            target.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
+            target.accept(new NodeVisitor() {
                 @Override
-                protected Node enterDefault(Node node) {
+                protected boolean enterDefault(Node node) {
                     throw new AssertionError("Unexpected node " + node + " in store epilogue");
                 }
 
                 @Override
-                public Node enterUnaryNode(final UnaryNode node) {
-                    if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
+                public boolean enterUnaryNode(final UnaryNode node) {
+                    if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
                         method.convert(node.rhs().getType());
                     }
-                    return node;
+                    return true;
                 }
 
                 @Override
-                public Node enterIdentNode(final IdentNode node) {
+                public boolean enterIdentNode(final IdentNode node) {
                     final Symbol symbol = node.getSymbol();
                     assert symbol != null;
                     if (symbol.isScope()) {
@@ -3218,20 +3254,20 @@
                     } else {
                         method.store(symbol);
                     }
-                    return null;
+                    return false;
 
                 }
 
                 @Override
-                public Node enterAccessNode(final AccessNode node) {
+                public boolean enterAccessNode(final AccessNode node) {
                     method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
-                    return null;
+                    return false;
                 }
 
                 @Override
-                public Node enterIndexNode(final IndexNode node) {
+                public boolean enterIndexNode(final IndexNode node) {
                     method.dynamicSetIndex(getCallSiteFlags());
-                    return null;
+                    return false;
                 }
             });
 
@@ -3250,10 +3286,23 @@
                 method.load(quick);
             }
         }
-
     }
 
-    private void newFunctionObject(final FunctionNode functionNode) {
+    private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) {
+        final LexicalContext lc = getLexicalContext();
+        assert lc.peek() == functionNode;
+        // We don't emit a ScriptFunction on stack for:
+        // 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it
+        //    as a callee), and
+        // 2. for functions that are immediately called upon definition and they don't need a callee, e.g. (function(){})().
+        //    Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded
+        //    visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their
+        //    static method's parameter list.
+        if(lc.getOutermostFunction() == functionNode ||
+                (!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) {
+            return;
+        }
+
         final boolean isLazy  = functionNode.isLazy();
 
         new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) {
@@ -3265,7 +3314,7 @@
                 loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap()));
 
                 if (isLazy || functionNode.needsParentScope()) {
-                    m.loadScope();
+                    m.loadCompilerConstant(SCOPE);
                 } else {
                     m.loadNull();
                 }
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu May 16 11:47:51 2013 +0100
@@ -15,6 +15,7 @@
 import java.util.HashSet;
 import java.util.Set;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -29,8 +30,8 @@
 import jdk.nashorn.internal.runtime.Timing;
 
 /**
- * A compilation phase is a step in the processes of turning a JavaScript FunctionNode
- * into bytecode. It has an optional return value.
+ * A compilation phase is a step in the processes of turning a JavaScript
+ * FunctionNode into bytecode. It has an optional return value.
  */
 enum CompilationPhase {
 
@@ -41,77 +42,87 @@
      */
     LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn0) {
 
             /*
-             * For lazy compilation, we might be given a node previously marked as lazy
-             * to compile as the outermost function node in the compiler. Unmark it
-             * so it can be compiled and not cause recursion. Make sure the return type
-             * is unknown so it can be correctly deduced. Return types are always
-             * Objects in Lazy nodes as we haven't got a change to generate code for
-             * them and decude its parameter specialization
+             * For lazy compilation, we might be given a node previously marked
+             * as lazy to compile as the outermost function node in the
+             * compiler. Unmark it so it can be compiled and not cause
+             * recursion. Make sure the return type is unknown so it can be
+             * correctly deduced. Return types are always Objects in Lazy nodes
+             * as we haven't got a change to generate code for them and decude
+             * its parameter specialization
              *
-             * TODO: in the future specializations from a callsite will be passed here
-             * so we can generate a better non-lazy version of a function from a trampoline
+             * TODO: in the future specializations from a callsite will be
+             * passed here so we can generate a better non-lazy version of a
+             * function from a trampoline
              */
-            //compute the signature from the callsite - todo - now just clone object params
+
             final FunctionNode outermostFunctionNode = compiler.getFunctionNode();
-            outermostFunctionNode.setIsLazy(false);
-            outermostFunctionNode.setReturnType(Type.UNKNOWN);
+            assert outermostFunctionNode == fn0;
 
             final Set<FunctionNode> neverLazy = new HashSet<>();
-            final Set<FunctionNode> lazy = new HashSet<>();
+            final Set<FunctionNode> lazy      = new HashSet<>();
+
+            FunctionNode newFunctionNode = outermostFunctionNode;
 
-            outermostFunctionNode.accept(new NodeVisitor() {
-                // self references are done with invokestatic and thus cannot have trampolines - never lazy
+            newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() {
+                // self references are done with invokestatic and thus cannot
+                // have trampolines - never lazy
                 @Override
-                public Node enterCallNode(final CallNode node) {
+                public boolean enterCallNode(final CallNode node) {
                     final Node callee = node.getFunction();
                     if (callee instanceof FunctionNode) {
                         neverLazy.add(((FunctionNode)callee));
-                        return null;
+                        return false;
                     }
-                    return node;
+                    return true;
                 }
 
+                //any function that isn't the outermost one must be marked as lazy
                 @Override
-                public Node enterFunctionNode(final FunctionNode node) {
-                    if (node == outermostFunctionNode) {
-                        return node;
-                    }
+                public boolean enterFunctionNode(final FunctionNode node) {
                     assert compiler.isLazy();
                     lazy.add(node);
-
-                    //also needs scope, potentially needs arguments etc etc
-
-                    return node;
+                    return true;
                 }
             });
 
+            //at least one method is non lazy - the outermost one
+            neverLazy.add(newFunctionNode);
+
             for (final FunctionNode node : neverLazy) {
-                Compiler.LOG.fine("Marking " + node.getName() + " as non lazy, as it's a self reference");
-                node.setIsLazy(false);
+                Compiler.LOG.fine(
+                        "Marking ",
+                        node.getName(),
+                        " as non lazy, as it's a self reference");
                 lazy.remove(node);
             }
 
-            outermostFunctionNode.accept(new NodeOperatorVisitor() {
-                private final LexicalContext lexicalContext = new LexicalContext();
+            newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeOperatorVisitor() {
                 @Override
-                public Node enterFunctionNode(FunctionNode functionNode) {
-                    lexicalContext.push(functionNode);
-                    if(lazy.contains(functionNode)) {
-                        Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy");
-                        functionNode.setIsLazy(true);
-                        lexicalContext.getParentFunction(functionNode).setHasLazyChildren();
+                public Node leaveFunctionNode(final FunctionNode functionNode) {
+                    final LexicalContext lc = getLexicalContext();
+                    if (lazy.contains(functionNode)) {
+                        Compiler.LOG.fine(
+                                "Marking ",
+                                functionNode.getName(),
+                                " as lazy");
+                        final FunctionNode parent = lc.getParentFunction(functionNode);
+                        assert parent != null;
+                        lc.setFlag(parent, FunctionNode.HAS_LAZY_CHILDREN);
+                        lc.setFlag(parent.getBody(), Block.NEEDS_SCOPE);
+                        lc.setFlag(functionNode, FunctionNode.IS_LAZY);
+                        return functionNode;
                     }
-                    return functionNode;
-                }
-                @Override
-                public Node leaveFunctionNode(FunctionNode functionNode) {
-                    lexicalContext.pop(functionNode);
-                    return functionNode;
+
+                    return functionNode.
+                        clearFlag(lc, FunctionNode.IS_LAZY).
+                        setReturnType(lc, Type.UNKNOWN);
                 }
             });
+
+            return newFunctionNode;
         }
 
         @Override
@@ -121,13 +132,13 @@
     },
 
     /*
-     * Constant folding pass
-     *   Simple constant folding that will make elementary constructs go away
+     * Constant folding pass Simple constant folding that will make elementary
+     * constructs go away
      */
     CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED, PARSED)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
-            fn.accept(new FoldConstants());
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
+            return (FunctionNode)fn.accept(new FoldConstants());
         }
 
         @Override
@@ -137,18 +148,16 @@
     },
 
     /*
-     * Lower (Control flow pass)
-     *   Finalizes the control flow. Clones blocks for finally constructs and
-     *   similar things. Establishes termination criteria for nodes
-     *   Guarantee return instructions to method making sure control flow
-     *   cannot fall off the end. Replacing high level nodes with lower such
-     *   as runtime nodes where applicable.
-     *
+     * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
+     * finally constructs and similar things. Establishes termination criteria
+     * for nodes Guarantee return instructions to method making sure control
+     * flow cannot fall off the end. Replacing high level nodes with lower such
+     * as runtime nodes where applicable.
      */
     LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
-            fn.accept(new Lower());
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
+            return (FunctionNode)fn.accept(new Lower());
         }
 
         @Override
@@ -158,13 +167,27 @@
     },
 
     /*
-     * Attribution
-     *   Assign symbols and types to all nodes.
+     * Attribution Assign symbols and types to all nodes.
      */
     ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
-            fn.accept(new Attr());
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
+            return (FunctionNode)initReturnTypes(fn).accept(new Attr());
+        }
+
+        /**
+         * Pessimistically set all lazy functions' return types to Object
+         * @param functionNode node where to start iterating
+         */
+        private FunctionNode initReturnTypes(final FunctionNode functionNode) {
+            return (FunctionNode)functionNode.accept(new NodeVisitor() {
+                @Override
+                public Node leaveFunctionNode(final FunctionNode node) {
+                    return node.isLazy() ?
+                           node.setReturnType(getLexicalContext(), Type.OBJECT) :
+                           node.setReturnType(getLexicalContext(), Type.UNKNOWN);
+                }
+            });
         }
 
         @Override
@@ -174,25 +197,35 @@
     },
 
     /*
-     * Splitter
-     *   Split the AST into several compile units based on a size heuristic
-     *   Splitter needs attributed AST for weight calculations (e.g. is
-     *   a + b a ScriptRuntime.ADD with call overhead or a dadd with much
-     *   less). Split IR can lead to scope information being changed.
+     * Splitter Split the AST into several compile units based on a size
+     * heuristic Splitter needs attributed AST for weight calculations (e.g. is
+     * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less).
+     * Split IR can lead to scope information being changed.
      */
     SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
             final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName());
 
-            new Splitter(compiler, fn, outermostCompileUnit).split();
+            final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn);
 
-            assert fn.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + fn.getCompileUnit() + ") != " + outermostCompileUnit;
+            assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit;
 
-            if (fn.isStrictMode()) {
+            if (newFunctionNode.isStrict()) {
                 assert compiler.getStrictMode();
                 compiler.setStrictMode(true);
             }
+
+            /*
+            newFunctionNode.accept(new NodeVisitor() {
+                @Override
+                public boolean enterFunctionNode(final FunctionNode functionNode) {
+                    assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit";
+                    return true;
+                }
+            });*/
+
+            return newFunctionNode;
         }
 
         @Override
@@ -204,30 +237,32 @@
     /*
      * FinalizeTypes
      *
-     *   This pass finalizes the types for nodes. If Attr created wider types than
-     *   known during the first pass, convert nodes are inserted or access nodes
-     *   are specialized where scope accesses.
+     * This pass finalizes the types for nodes. If Attr created wider types than
+     * known during the first pass, convert nodes are inserted or access nodes
+     * are specialized where scope accesses.
      *
-     *   Runtime nodes may be removed and primitivized or reintroduced depending
-     *   on information that was established in Attr.
+     * Runtime nodes may be removed and primitivized or reintroduced depending
+     * on information that was established in Attr.
      *
      * Contract: all variables must have slot assignments and scope assignments
      * before type finalization.
      */
     TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
             final ScriptEnvironment env = compiler.getEnv();
 
-            fn.accept(new FinalizeTypes());
+            final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes());
 
             if (env._print_lower_ast) {
-                env.getErr().println(new ASTWriter(fn));
+                env.getErr().println(new ASTWriter(newFunctionNode));
             }
 
             if (env._print_lower_parse) {
-                env.getErr().println(new PrintVisitor(fn));
-           }
+                env.getErr().println(new PrintVisitor(newFunctionNode));
+            }
+
+            return newFunctionNode;
         }
 
         @Override
@@ -239,31 +274,21 @@
     /*
      * Bytecode generation:
      *
-     *   Generate the byte code class(es) resulting from the compiled FunctionNode
+     * Generate the byte code class(es) resulting from the compiled FunctionNode
      */
     BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) {
         @Override
-        void transform(final Compiler compiler, final FunctionNode fn) {
+        FunctionNode transform(final Compiler compiler, final FunctionNode fn) {
             final ScriptEnvironment env = compiler.getEnv();
+            FunctionNode newFunctionNode = fn;
 
             try {
                 final CodeGenerator codegen = new CodeGenerator(compiler);
-                fn.accept(codegen);
+                newFunctionNode = (FunctionNode)newFunctionNode.accept(codegen);
                 codegen.generateScopeCalls();
-                fn.accept(new NodeOperatorVisitor() {
-                    @Override
-                    public Node enterFunctionNode(FunctionNode functionNode) {
-                        if(functionNode.isLazy()) {
-                            functionNode.resetResolved();
-                            return null;
-                        }
-                        return fn;
-                    }
-                });
-
             } catch (final VerifyError e) {
                 if (env._verify_code || env._print_code) {
-                    env.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage());
+                    env.getErr().println(e.getClass().getSimpleName() + ": "  + e.getMessage());
                     if (env._dump_on_error) {
                         e.printStackTrace(env.getErr());
                     }
@@ -283,25 +308,25 @@
 
                 compiler.addClass(className, bytecode);
 
-                //should could be printed to stderr for generate class?
+                // should could be printed to stderr for generate class?
                 if (env._print_code) {
                     final StringBuilder sb = new StringBuilder();
-                    sb.append("class: " + className).
-                        append('\n').
-                        append(ClassEmitter.disassemble(bytecode)).
-                        append("=====");
+                    sb.append("class: " + className).append('\n')
+                            .append(ClassEmitter.disassemble(bytecode))
+                            .append("=====");
                     env.getErr().println(sb);
                 }
 
-                //should we verify the generated code?
+                // should we verify the generated code?
                 if (env._verify_code) {
                     compiler.getCodeInstaller().verify(bytecode);
                 }
 
-                //should code be dumped to disk - only valid in compile_only mode?
+                // should code be dumped to disk - only valid in compile_only
+                // mode?
                 if (env._dest_dir != null && env._compile_only) {
                     final String fileName = className.replace('.', File.separatorChar) + ".class";
-                    final int    index    = fileName.lastIndexOf(File.separatorChar);
+                    final int index = fileName.lastIndexOf(File.separatorChar);
 
                     if (index != -1) {
                         final File dir = new File(fileName.substring(0, index));
@@ -314,11 +339,18 @@
                                 fos.write(bytecode);
                             }
                         } catch (final IOException e) {
-                            Compiler.LOG.warning("Skipping class dump for " + className + ": " + ECMAErrors.getMessage("io.error.cant.write", dir.toString()));
+                            Compiler.LOG.warning("Skipping class dump for ",
+                                    className,
+                                    ": ",
+                                    ECMAErrors.getMessage(
+                                        "io.error.cant.write",
+                                        dir.toString()));
                         }
                     }
                 }
             }
+
+            return newFunctionNode;
         }
 
         @Override
@@ -340,26 +372,28 @@
         return functionNode.hasState(pre);
     }
 
-    protected void begin(final FunctionNode functionNode) {
+    protected FunctionNode begin(final FunctionNode functionNode) {
         if (pre != null) {
-            //check that everything in pre is present
+            // check that everything in pre is present
             for (final CompilationState state : pre) {
                 assert functionNode.hasState(state);
             }
-            //check that nothing else is present
+            // check that nothing else is present
             for (final CompilationState state : CompilationState.values()) {
                 assert !(functionNode.hasState(state) && !pre.contains(state));
             }
         }
 
         startTime = System.currentTimeMillis();
+        return functionNode;
     }
 
-    protected void end(final FunctionNode functionNode) {
+    protected FunctionNode end(final FunctionNode functionNode) {
         endTime = System.currentTimeMillis();
         Timing.accumulateTime(toString(), endTime - startTime);
 
         isFinished = true;
+        return functionNode;
     }
 
     boolean isFinished() {
@@ -374,15 +408,13 @@
         return endTime;
     }
 
-    abstract void transform(final Compiler compiler, final FunctionNode functionNode) throws CompilationException;
+    abstract FunctionNode transform(final Compiler compiler, final FunctionNode functionNode) throws CompilationException;
 
-    final void apply(final Compiler compiler, final FunctionNode functionNode) throws CompilationException {
+    final FunctionNode apply(final Compiler compiler, final FunctionNode functionNode) throws CompilationException {
         if (!isApplicable(functionNode)) {
-            throw new CompilationException("compile phase not applicable: " + this);
+            throw new CompilationException("compile phase not applicable: " + this + " to " + functionNode.getName() + " state=" + functionNode.getState());
         }
-        begin(functionNode);
-        transform(compiler, functionNode);
-        end(functionNode);
+        return end(transform(compiler, begin(functionNode)));
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Thu May 16 11:47:51 2013 +0100
@@ -25,12 +25,16 @@
 
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.DEFAULT_SCRIPT_NAME;
 import static jdk.nashorn.internal.codegen.CompilerConstants.LAZY;
+import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 
 import java.io.File;
 import java.lang.reflect.Field;
@@ -46,13 +50,12 @@
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.logging.Level;
+
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.CodeInstaller;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -80,8 +83,6 @@
 
     private final ConstantData constantData;
 
-    private final FunctionNode functionNode;
-
     private final CompilationSequence sequence;
 
     private final ScriptEnvironment env;
@@ -90,6 +91,8 @@
 
     private boolean strict;
 
+    private FunctionNode functionNode;
+
     private CodeInstaller<ScriptEnvironment> installer;
 
     /** logger for compiler, trampolines, splits and related code generation events
@@ -103,8 +106,12 @@
      * during a compile.
      */
     private static String[] RESERVED_NAMES = {
-        SCOPE.tag(),
-        THIS.tag()
+        SCOPE.symbolName(),
+        THIS.symbolName(),
+        RETURN.symbolName(),
+        CALLEE.symbolName(),
+        VARARGS.symbolName(),
+        ARGUMENTS.symbolName()
     };
 
     /**
@@ -186,7 +193,7 @@
 
     private static String lazyTag(final FunctionNode functionNode) {
         if (functionNode.isLazy()) {
-            return '$' + LAZY.tag() + '$' + functionNode.getName();
+            return '$' + LAZY.symbolName() + '$' + functionNode.getName();
         }
         return "";
     }
@@ -205,13 +212,13 @@
         this.functionNode  = functionNode;
         this.sequence      = sequence;
         this.installer     = installer;
-        this.strict        = strict || functionNode.isStrictMode();
+        this.strict        = strict || functionNode.isStrict();
         this.constantData  = new ConstantData();
         this.compileUnits  = new HashSet<>();
         this.bytecode      = new HashMap<>();
 
         final StringBuilder sb = new StringBuilder();
-        sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.tag() + lazyTag(functionNode))).
+        sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))).
                 append('$').
                 append(safeSourceName(functionNode.getSource()));
 
@@ -253,9 +260,9 @@
      * Execute the compilation this Compiler was created with
      * @params param types if known, for specialization
      * @throws CompilationException if something goes wrong
-     * @return this compiler, for possible chaining
+     * @return function node that results from code transforms
      */
-    public Compiler compile() throws CompilationException {
+    public FunctionNode compile() throws CompilationException {
         return compile(null);
     }
 
@@ -263,9 +270,9 @@
      * Execute the compilation this Compiler was created with
      * @param paramTypes param types if known, for specialization
      * @throws CompilationException if something goes wrong
-     * @return this compiler, for possible chaining
+     * @return function node that results from code transforms
      */
-    public Compiler compile(final Class<?> paramTypes) throws CompilationException {
+    public FunctionNode compile(final Class<?> paramTypes) throws CompilationException {
         for (final String reservedName : RESERVED_NAMES) {
             functionNode.uniqueName(reservedName);
         }
@@ -276,7 +283,7 @@
         long time = 0L;
 
         for (final CompilationPhase phase : sequence) {
-            phase.apply(this, functionNode);
+            this.functionNode = phase.apply(this, functionNode);
 
             final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L;
             time += duration;
@@ -295,7 +302,7 @@
                         append(" ms ");
                 }
 
-                LOG.fine(sb.toString());
+                LOG.fine(sb);
             }
         }
 
@@ -311,14 +318,14 @@
                     append(" ms");
             }
 
-            LOG.info(sb.toString());
+            LOG.info(sb);
         }
 
-        return this;
+        return functionNode;
     }
 
     private Class<?> install(final String className, final byte[] code) {
-        LOG.fine("Installing class " + className);
+        LOG.fine("Installing class ", className);
 
         final Class<?> clazz = installer.install(Compiler.binaryName(className), code);
 
@@ -330,8 +337,8 @@
                 @Override
                 public Void run() throws Exception {
                     //use reflection to write source and constants table to installed classes
-                    final Field sourceField    = clazz.getDeclaredField(SOURCE.tag());
-                    final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag());
+                    final Field sourceField    = clazz.getDeclaredField(SOURCE.symbolName());
+                    final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName());
                     sourceField.setAccessible(true);
                     constantsField.setAccessible(true);
                     sourceField.set(null, source);
@@ -380,17 +387,6 @@
             unit.setCode(installedClasses.get(unit.getUnitClassName()));
         }
 
-        functionNode.accept(new NodeVisitor() {
-            @Override
-            public Node enterFunctionNode(final FunctionNode node) {
-                if (node.isLazy()) {
-                    return null;
-                }
-                node.setState(CompilationState.INSTALLED);
-                return node;
-            }
-        });
-
         final StringBuilder sb;
         if (LOG.isEnabled()) {
             sb = new StringBuilder();
@@ -416,7 +412,7 @@
         }
 
         if (sb != null) {
-            LOG.info(sb.toString());
+            LOG.info(sb);
         }
 
         return rootClass;
@@ -495,7 +491,7 @@
     private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) {
         final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight);
         compileUnits.add(compileUnit);
-        LOG.fine("Added compile unit " + compileUnit);
+        LOG.fine("Added compile unit ", compileUnit);
         return compileUnit;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Thu May 16 11:47:51 2013 +0100
@@ -52,9 +52,6 @@
     /** lazy prefix for classes of jitted methods */
     LAZY("Lazy"),
 
-    /** leaf tag used for functions that require no scope */
-    LEAF("__leaf__"),
-
     /** constructor name */
     INIT("<init>"),
 
@@ -90,55 +87,55 @@
     THIS("this"),
 
     /** this debugger symbol */
-    THIS_DEBUGGER("__this__"),
+    THIS_DEBUGGER(":this"),
 
     /** scope name, type and slot */
-    SCOPE("__scope__", ScriptObject.class, 2),
+    SCOPE(":scope", ScriptObject.class, 2),
 
     /** the return value variable name were intermediate results are stored for scripts */
-    SCRIPT_RETURN("__return__"),
+    RETURN(":return"),
 
     /** the callee value variable when necessary */
-    CALLEE("__callee__", ScriptFunction.class),
+    CALLEE(":callee", ScriptFunction.class),
 
     /** the varargs variable when necessary */
-    VARARGS("__varargs__"),
+    VARARGS(":varargs"),
 
     /** the arguments vector when necessary and the slot */
     ARGUMENTS("arguments", Object.class, 2),
 
     /** prefix for iterators for for (x in ...) */
-    ITERATOR_PREFIX("$iter"),
+    ITERATOR_PREFIX(":iter"),
 
     /** prefix for tag variable used for switch evaluation */
-    SWITCH_TAG_PREFIX("$tag"),
+    SWITCH_TAG_PREFIX(":tag"),
 
     /** prefix for all exceptions */
-    EXCEPTION_PREFIX("$exception"),
+    EXCEPTION_PREFIX(":exception"),
 
     /** prefix for quick slots generated in Store */
-    QUICK_PREFIX("$quick"),
+    QUICK_PREFIX(":quick"),
 
     /** prefix for temporary variables */
-    TEMP_PREFIX("$temp"),
+    TEMP_PREFIX(":temp"),
 
     /** prefix for literals */
-    LITERAL_PREFIX("$lit"),
-
-    /** prefix for map */
-    MAP("$map", 1),
+    LITERAL_PREFIX(":lit"),
 
     /** prefix for regexps */
-    REGEX_PREFIX("$regex"),
+    REGEX_PREFIX(":regex"),
 
     /** "this" used in non-static Java methods; always in slot 0 */
-    JAVA_THIS("this", 0),
+    JAVA_THIS(null, 0),
+
+    /** Map parameter in scope object constructors; always in slot 1 */
+    INIT_MAP(null, 1),
 
-    /** init scope */
-    INIT_SCOPE("$scope", 2),
+    /** Parent scope parameter in scope object constructors; always in slot 2 */
+    INIT_SCOPE(null, 2),
 
-    /** init arguments */
-    INIT_ARGUMENTS("$arguments", 3),
+    /** Arguments parameter in scope object constructors; in slot 3 when present */
+    INIT_ARGUMENTS(null, 3),
 
     /** prefix for all ScriptObject subclasses with fields, @see ObjectGenerator */
     JS_OBJECT_PREFIX("JO"),
@@ -167,30 +164,30 @@
     /** get array suffix */
     GET_ARRAY_SUFFIX("$array");
 
-    private final String tag;
+    private final String symbolName;
     private final Class<?> type;
     private final int slot;
 
     private CompilerConstants() {
-        this.tag = name();
+        this.symbolName = name();
         this.type = null;
         this.slot = -1;
     }
 
-    private CompilerConstants(final String tag) {
-        this(tag, -1);
+    private CompilerConstants(final String symbolName) {
+        this(symbolName, -1);
     }
 
-    private CompilerConstants(final String tag, final int slot) {
-        this(tag, null, slot);
+    private CompilerConstants(final String symbolName, final int slot) {
+        this(symbolName, null, slot);
     }
 
-    private CompilerConstants(final String tag, final Class<?> type) {
-        this(tag, type, -1);
+    private CompilerConstants(final String symbolName, final Class<?> type) {
+        this(symbolName, type, -1);
     }
 
-    private CompilerConstants(final String tag, final Class<?> type, final int slot) {
-        this.tag  = tag;
+    private CompilerConstants(final String symbolName, final Class<?> type, final int slot) {
+        this.symbolName  = symbolName;
         this.type = type;
         this.slot = slot;
     }
@@ -202,8 +199,8 @@
      *
      * @return the tag
      */
-    public final String tag() {
-        return tag;
+    public final String symbolName() {
+        return symbolName;
     }
 
     /**
@@ -277,7 +274,7 @@
      * @return Call representing void constructor for type
      */
     public static Call constructorNoLookup(final Class<?> clazz) {
-        return specialCallNoLookup(clazz, INIT.tag(), void.class);
+        return specialCallNoLookup(clazz, INIT.symbolName(), void.class);
     }
 
     /**
@@ -290,7 +287,7 @@
      * @return Call representing constructor for type
      */
     public static Call constructorNoLookup(final String className, final Class<?>... ptypes) {
-        return specialCallNoLookup(className, INIT.tag(), methodDescriptor(void.class, ptypes));
+        return specialCallNoLookup(className, INIT.symbolName(), methodDescriptor(void.class, ptypes));
     }
 
     /**
@@ -303,7 +300,7 @@
      * @return Call representing constructor for type
      */
     public static Call constructorNoLookup(final Class<?> clazz, final Class<?>... ptypes) {
-        return specialCallNoLookup(clazz, INIT.tag(), void.class, ptypes);
+        return specialCallNoLookup(clazz, INIT.symbolName(), void.class, ptypes);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu May 16 11:47:51 2013 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.codegen;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
 import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
@@ -86,7 +87,7 @@
      * @param method the method emitter to use
      */
     protected void loadScope(final MethodEmitter method) {
-        method.loadScope();
+        method.loadCompilerConstant(SCOPE);
     }
 
     /**
@@ -105,7 +106,7 @@
             loadScope(method);
 
             if (hasArguments()) {
-                method.loadArguments();
+                method.loadCompilerConstant(ARGUMENTS);
                 method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class, ARGUMENTS.type()));
             } else {
                 method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class));
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Thu May 16 11:47:51 2013 +0100
@@ -25,7 +25,12 @@
 
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
+
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
@@ -33,10 +38,8 @@
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.CallNode;
-import jdk.nashorn.internal.ir.CallNode.EvalArgs;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
@@ -85,18 +88,11 @@
 
     private static final DebugLogger LOG = new DebugLogger("finalize");
 
-    private final LexicalContext lexicalContext = new LexicalContext();
-
     FinalizeTypes() {
     }
 
     @Override
     public Node leaveCallNode(final CallNode callNode) {
-        final EvalArgs evalArgs = callNode.getEvalArgs();
-        if (evalArgs != null) {
-            evalArgs.setCode(evalArgs.getCode().accept(this));
-        }
-
         // AccessSpecializer - call return type may change the access for this location
         final Node function = callNode.getFunction();
         if (function instanceof FunctionNode) {
@@ -133,8 +129,7 @@
     @Override
     public Node leaveNEW(final UnaryNode unaryNode) {
         assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject();
-        ((CallNode)unaryNode.rhs()).setIsNew();
-        return unaryNode;
+        return unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew());
     }
 
     @Override
@@ -254,7 +249,7 @@
     @Override
     public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
         assert binaryNode.getSymbol() != null;
-        final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs()));
+        final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs()));
         // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
         // in that case, update the node type as well
         propagateType(newBinaryNode, newBinaryNode.lhs().getType());
@@ -354,41 +349,30 @@
     }
 
     @Override
-    public Node enterBlock(final Block block) {
-        lexicalContext.push(block);
+    public boolean enterBlock(final Block block) {
         updateSymbols(block);
-        return block;
+        return true;
     }
 
+    /*
     @Override
-    public Node leaveBlock(Block block) {
-        lexicalContext.pop(block);
-        return super.leaveBlock(block);
-    }
+    public Node leaveBlock(final Block block) {
+        final LexicalContext lc = getLexicalContext();
+        return block;//.setFlag(lc, lc.getFlags(block));
+    }*/
 
     @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
         final Node exceptionCondition = catchNode.getExceptionCondition();
         if (exceptionCondition != null) {
-            catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
+            return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
         }
         return catchNode;
     }
 
     @Override
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        return enterWhileNode(doWhileNode);
-    }
-
-    @Override
-    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
-        return leaveWhileNode(doWhileNode);
-    }
-
-    @Override
     public Node leaveExecuteNode(final ExecuteNode executeNode) {
-        executeNode.setExpression(discard(executeNode.getExpression()));
-        return executeNode;
+        return executeNode.setExpression(discard(executeNode.getExpression()));
     }
 
     @Override
@@ -397,69 +381,54 @@
         final Node test   = forNode.getTest();
         final Node modify = forNode.getModify();
 
-        if (forNode.isForIn()) {
-            forNode.setModify(convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
-            return forNode;
-        }
-
-        if (init != null) {
-            forNode.setInit(discard(init));
-        }
+        final LexicalContext lc = getLexicalContext();
 
-        if (test != null) {
-            forNode.setTest(convert(test, Type.BOOLEAN));
-        } else {
-            assert forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getCurrentFunctionNode();
+        if (forNode.isForIn()) {
+            return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
         }
+        assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getLexicalContext().getCurrentFunction();
 
-        if (modify != null) {
-            forNode.setModify(discard(modify));
-        }
-
-        return forNode;
+        return forNode.
+            setInit(lc, init == null ? null : discard(init)).
+            setTest(lc, test == null ? null : convert(test, Type.BOOLEAN)).
+            setModify(lc, modify == null ? null : discard(modify));
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
         if (functionNode.isLazy()) {
-            return null;
+            return false;
         }
 
-        lexicalContext.push(functionNode);
         // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
         // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
         // need for the callee.
         if (!functionNode.needsCallee()) {
-            functionNode.getCalleeNode().getSymbol().setNeedsSlot(false);
+            functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
         }
         // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope or its
         // own scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope earlier than
         // this phase.
-        if (!(functionNode.needsScope() || functionNode.needsParentScope())) {
-            functionNode.getScopeNode().getSymbol().setNeedsSlot(false);
+        if (!(functionNode.getBody().needsScope() || functionNode.needsParentScope())) {
+            functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
         }
 
-        updateSymbols(functionNode);
-        functionNode.setState(CompilationState.FINALIZED);
-
-        return functionNode;
+        return true;
     }
 
     @Override
-    public Node leaveFunctionNode(FunctionNode functionNode) {
-        lexicalContext.pop(functionNode);
-        return super.leaveFunctionNode(functionNode);
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        return functionNode.setState(getLexicalContext(), CompilationState.FINALIZED);
     }
 
     @Override
     public Node leaveIfNode(final IfNode ifNode) {
-        ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
-        return ifNode;
+        return ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    public Node enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         if (literalNode instanceof ArrayLiteralNode) {
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
             final Node[]           array            = arrayLiteralNode.getValue();
@@ -473,14 +442,14 @@
             }
         }
 
-        return null;
+        return false;
     }
 
     @Override
     public Node leaveReturnNode(final ReturnNode returnNode) {
         final Node expr = returnNode.getExpression();
         if (expr != null) {
-            returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType()));
+            return returnNode.setExpression(convert(expr, getLexicalContext().getCurrentFunction().getReturnType()));
         }
         return returnNode;
     }
@@ -496,21 +465,24 @@
 
     @Override
     public Node leaveSwitchNode(final SwitchNode switchNode) {
+        final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
+
+        if (allInteger) {
+            return switchNode;
+        }
+
         final Node           expression  = switchNode.getExpression();
         final List<CaseNode> cases       = switchNode.getCases();
-        final boolean        allInteger  = switchNode.getTag().getSymbolType().isInteger();
+        final List<CaseNode> newCases    = new ArrayList<>();
 
-        if (!allInteger) {
-            switchNode.setExpression(convert(expression, Type.OBJECT));
-            for (final CaseNode caseNode : cases) {
-                final Node test = caseNode.getTest();
-                if (test != null) {
-                    caseNode.setTest(convert(test, Type.OBJECT));
-                }
-            }
+        for (final CaseNode caseNode : cases) {
+            final Node test = caseNode.getTest();
+            newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
         }
 
-        return switchNode;
+        return switchNode.
+            setExpression(getLexicalContext(), convert(expression, Type.OBJECT)).
+            setCases(getLexicalContext(), newCases);
     }
 
     @Override
@@ -520,8 +492,7 @@
 
     @Override
     public Node leaveThrowNode(final ThrowNode throwNode) {
-        throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
-        return throwNode;
+        return throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
     }
 
     @Override
@@ -544,23 +515,24 @@
     public Node leaveWhileNode(final WhileNode whileNode) {
         final Node test = whileNode.getTest();
         if (test != null) {
-            whileNode.setTest(convert(test, Type.BOOLEAN));
+            return whileNode.setTest(getLexicalContext(), convert(test, Type.BOOLEAN));
         }
         return whileNode;
     }
 
     @Override
     public Node leaveWithNode(final WithNode withNode) {
-        withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
-        return withNode;
+        return withNode.setExpression(getLexicalContext(), convert(withNode.getExpression(), Type.OBJECT));
     }
 
     private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) {
-        if (!symbol.isScope()) {
-            LOG.finest("updateSymbols: " + symbol + " => scope, because all vars in " + functionNode.getName() + " are in scope");
-        }
-        if (loseSlot && symbol.hasSlot()) {
-            LOG.finest("updateSymbols: " + symbol + " => no slot, because all vars in " + functionNode.getName() + " are in scope");
+        if (LOG.isEnabled()) {
+            if (!symbol.isScope()) {
+                LOG.finest("updateSymbols: ", symbol, " => scope, because all vars in ", functionNode.getName(), " are in scope");
+            }
+            if (loseSlot && symbol.hasSlot()) {
+                LOG.finest("updateSymbols: ", symbol, " => no slot, because all vars in ", functionNode.getName(), " are in scope");
+            }
         }
     }
 
@@ -574,29 +546,28 @@
             return; // nothing to do
         }
 
-        final FunctionNode functionNode = lexicalContext.getFunction(block);
-        assert !(block instanceof FunctionNode) || functionNode == block;
+        final LexicalContext lc             = getLexicalContext();
+        final FunctionNode   functionNode   = lc.getFunction(block);
+        final boolean        allVarsInScope = functionNode.allVarsInScope();
+        final boolean        isVarArg       = functionNode.isVarArg();
 
-        final List<Symbol> symbols        = block.getFrame().getSymbols();
-        final boolean      allVarsInScope = functionNode.allVarsInScope();
-        final boolean      isVarArg       = functionNode.isVarArg();
-
-        for (final Symbol symbol : symbols) {
-            if (symbol.isInternal() || symbol.isThis()) {
+        for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) {
+            final Symbol symbol = iter.next();
+            if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) {
                 continue;
             }
 
             if (symbol.isVar()) {
                 if (allVarsInScope || symbol.isScope()) {
                     updateSymbolsLog(functionNode, symbol, true);
-                    symbol.setIsScope();
+                    Symbol.setSymbolIsScope(lc, symbol);
                     symbol.setNeedsSlot(false);
                 } else {
                     assert symbol.hasSlot() : symbol + " should have a slot only, no scope";
                 }
             } else if (symbol.isParam() && (allVarsInScope || isVarArg || symbol.isScope())) {
                 updateSymbolsLog(functionNode, symbol, isVarArg);
-                symbol.setIsScope();
+                Symbol.setSymbolIsScope(lc, symbol);
                 symbol.setNeedsSlot(!isVarArg);
             }
         }
@@ -636,11 +607,7 @@
             //fallthru
         default:
             if (newRuntimeNode || widest.isObject()) {
-                final RuntimeNode runtimeNode = new RuntimeNode(binaryNode, request);
-                if (finalized) {
-                    runtimeNode.setIsFinal();
-                }
-                return runtimeNode;
+                return new RuntimeNode(binaryNode, request).setIsFinal(finalized);
             }
             break;
         }
@@ -667,7 +634,8 @@
     }
 
     private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
-        return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
+        Node b =  binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
+        return b;
     }
 
     /**
@@ -683,28 +651,28 @@
 
         node.accept(new NodeVisitor() {
             private void setCanBePrimitive(final Symbol symbol) {
-                LOG.info("*** can be primitive symbol " + symbol + " " + Debug.id(symbol));
+                LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol));
                 symbol.setCanBePrimitive(to);
             }
 
             @Override
-            public Node enterIdentNode(final IdentNode identNode) {
+            public boolean enterIdentNode(final IdentNode identNode) {
                 if (!exclude.contains(identNode)) {
                     setCanBePrimitive(identNode.getSymbol());
                 }
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterAccessNode(final AccessNode accessNode) {
+            public boolean enterAccessNode(final AccessNode accessNode) {
                 setCanBePrimitive(accessNode.getProperty().getSymbol());
-                return null;
+                return false;
             }
 
             @Override
-            public Node enterIndexNode(final IndexNode indexNode) {
+            public boolean enterIndexNode(final IndexNode indexNode) {
                 exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
-                return indexNode;
+                return true;
             }
         });
     }
@@ -785,12 +753,12 @@
     private static <T extends Node> T setTypeOverride(final T node, final Type to) {
         final Type from = node.getType();
         if (!node.getType().equals(to)) {
-            LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to);
+            LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
             if (!to.isObject() && from.isObject()) {
                 setCanBePrimitive(node, to);
             }
         }
-        LOG.info("Type override for lhs in '" + node + "' => " + to);
+        LOG.info("Type override for lhs in '", node, "' => ", to);
         return ((TypeOverride<T>)node).setType(to);
     }
 
@@ -814,8 +782,8 @@
     private Node convert(final Node node, final Type to) {
         assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
         assert node != null : "node is null";
-        assert node.getSymbol() != null : "node " + node + " has no symbol!";
-        assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getCurrentFunctionNode();
+        assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction() + " " + node.getSource();
+        assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction();
 
         final Type from = node.getType();
 
@@ -842,23 +810,23 @@
             resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
         }
 
-        LOG.info("CONVERT('" + node + "', " + to + ") => '" + resultNode + "'");
+        LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'");
 
+        final LexicalContext lc = getLexicalContext();
         //This is the only place in this file that can create new temporaries
         //FinalizeTypes may not introduce ANY node that is not a conversion.
-        getCurrentFunctionNode().newTemporary(getCurrentBlock().getFrame(), to, resultNode);
-        resultNode.copyTerminalFlags(node);
+        lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode);
+
+        assert !node.isTerminal();
 
         return resultNode;
     }
 
     private static Node discard(final Node node) {
-        node.setDiscard(true);
-
         if (node.getSymbol() != null) {
             final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node);
             //discard never has a symbol in the discard node - then it would be a nop
-            discard.copyTerminalFlags(node);
+            assert !node.isTerminal();
             return discard;
         }
 
@@ -883,7 +851,7 @@
         final Symbol symbol = node.getSymbol();
         if (symbol.isTemp()) {
             symbol.setTypeOverride(to);
-            LOG.info("Type override for temporary in '" + node + "' => " + to);
+            LOG.info("Type override for temporary in '", node, "' => ", to);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Thu May 16 11:47:51 2013 +0100
@@ -57,7 +57,7 @@
     public Node leaveUnaryNode(final UnaryNode unaryNode) {
         final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
         if (literalNode != null) {
-            LOG.info("Unary constant folded " + unaryNode + " to " + literalNode);
+            LOG.info("Unary constant folded ", unaryNode, " to ", literalNode);
             return literalNode;
         }
         return unaryNode;
@@ -67,24 +67,20 @@
     public Node leaveBinaryNode(final BinaryNode binaryNode) {
         final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
         if (literalNode != null) {
-            LOG.info("Binary constant folded " + binaryNode + " to " + literalNode);
+            LOG.info("Binary constant folded ", binaryNode, " to ", literalNode);
             return literalNode;
         }
         return binaryNode;
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        if (functionNode.isLazy()) {
-            return null;
-        }
-        return functionNode;
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        return !functionNode.isLazy();
     }
 
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
-        functionNode.setState(CompilationState.CONSTANT_FOLDED);
-        return functionNode;
+        return functionNode.setState(getLexicalContext(), CompilationState.CONSTANT_FOLDED);
     }
 
     @Override
@@ -251,7 +247,7 @@
                 value = lhs.getNumber() - rhs.getNumber();
                 break;
             case SHR:
-                return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & 0xffff_ffffL);
+                return LiteralNode.newInstance(source, token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
             case SAR:
                 return LiteralNode.newInstance(source, token, finish, lhs.getInt32() >> rhs.getInt32());
             case SHL:
--- a/nashorn/src/jdk/nashorn/internal/codegen/Frame.java	Wed May 08 11:22:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.codegen;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import jdk.nashorn.internal.ir.Symbol;
-
-/**
- * Tracks the variable area state.
- *
- */
-public final class Frame {
-    /** Previous frame. */
-    private Frame previous;
-
-    /** Current variables. */
-    private final ArrayList<Symbol> symbols;
-
-    /** Number of slots in previous frame. */
-    private int baseCount;
-
-    /** Number of slots in this frame. */
-    private int count;
-
-    /**
-     * Constructor.
-     *
-     * @param previous frame, the parent variable frame
-     */
-    public Frame(final Frame previous) {
-        this.previous  = previous;
-        this.symbols   = new ArrayList<>();
-        this.baseCount = getBaseCount();
-        this.count     = 0;
-    }
-
-    /**
-     * Copy constructor
-     * @param frame
-     * @param symbols
-     */
-    private Frame(final Frame frame, final List<Symbol> symbols) {
-        this.previous  = frame.getPrevious() == null ? null : new Frame(frame.getPrevious(), frame.getPrevious().getSymbols());
-        this.symbols   = new ArrayList<>(frame.getSymbols());
-        this.baseCount = frame.getBaseCount();
-        this.count     = frame.getCount();
-    }
-
-    /**
-     * Copy the frame
-     *
-     * @return a new frame with the identical contents
-     */
-    public Frame copy() {
-        return new Frame(this, getSymbols());
-    }
-
-    /**
-     * Add a new variable to the frame.
-     * @param symbol Symbol representing variable.
-     */
-    public void addSymbol(final Symbol symbol) {
-        final int slot = symbol.getSlot();
-        if (slot < 0) {
-            symbols.add(symbol);
-            count += symbol.slotCount();
-        }
-    }
-
-    /**
-     * Realign slot numbering prior to code generation.
-     * @return Number of slots in frame.
-     */
-    public int realign() {
-        baseCount = getBaseCount();
-        count     = 0;
-
-        for (final Symbol symbol : symbols) {
-            if (symbol.hasSlot()) {
-                symbol.setSlot(baseCount + count);
-                count += symbol.slotCount();
-            }
-        }
-
-        return count;
-    }
-
-    /**
-     * Return the slot count of previous frames.
-     * @return Number of slots in previous frames.
-     */
-    private int getBaseCount() {
-        return previous != null ? previous.getSlotCount() : 0;
-    }
-
-    /**
-     * Determine the number of slots to top of frame.
-     * @return Number of slots in total.
-     */
-    public int getSlotCount() {
-        return baseCount + count;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-        Frame f = this;
-        boolean hasPrev = false;
-        int pos = 0;
-
-        do {
-            if (hasPrev) {
-                sb.append("\n");
-            }
-
-            sb.append("#").
-                append(pos++).
-                append(" {baseCount:").
-                append(baseCount).
-                append(", ").
-                append("count:").
-                append(count).
-                append("} ");
-
-            for (final Symbol var : f.getSymbols()) {
-                sb.append('[').
-                    append(var.toString()).
-                    append(' ').
-                    append(var.hashCode()).
-                    append("] ");
-            }
-
-            f = f.getPrevious();
-            hasPrev = true;
-        } while (f != null);
-
-        return sb.toString();
-    }
-
-    /**
-     * Get variable count for this frame
-     * @return variable count
-     */
-    public int getCount() {
-        return count;
-    }
-
-    /**
-     * Get previous frame
-     * @return previous frame
-     */
-    public Frame getPrevious() {
-        return previous;
-    }
-
-    /**
-     * Set previous frame
-     * @param previous previous frame
-     */
-    public void setPrevious(final Frame previous) {
-        this.previous = previous;
-    }
-
-    /**
-     * Get symbols in frame
-     * @return a list of symbols in this frame
-     */
-    public List<Symbol> getSymbols() {
-        return Collections.unmodifiableList(symbols);
-    }
- }
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Thu May 16 11:47:51 2013 +0100
@@ -25,29 +25,21 @@
 
 package jdk.nashorn.internal.codegen;
 
-import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
-import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN;
+import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
-import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Deque;
-import java.util.Iterator;
 import java.util.List;
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockLexicalContext;
 import jdk.nashorn.internal.ir.BreakNode;
 import jdk.nashorn.internal.ir.CallNode;
-import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -56,10 +48,10 @@
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LabeledNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.SwitchNode;
@@ -90,356 +82,167 @@
 
 final class Lower extends NodeOperatorVisitor {
 
-    /**
-     * Nesting level stack. Currently just used for loops to avoid the problem
-     * with terminal bodies that end with throw/return but still do continues to
-     * outer loops or same loop.
-     */
-    private final Deque<Node> nesting;
-
     private static final DebugLogger LOG = new DebugLogger("lower");
 
-    private Node lastStatement;
-
-    private List<Node> statements;
-
-    private LexicalContext lexicalContext = new LexicalContext();
-
     /**
      * Constructor.
      *
      * @param compiler the compiler
      */
     Lower() {
-        this.nesting    = new ArrayDeque<>();
-        this.statements = new ArrayList<>();
+        super(new BlockLexicalContext() {
+
+            @Override
+            public List<Node> popStatements() {
+                List<Node> newStatements = new ArrayList<>();
+                boolean terminated = false;
+
+                final List<Node> statements = super.popStatements();
+                for (final Node statement : statements) {
+                    if (!terminated) {
+                        newStatements.add(statement);
+                        if (statement.isTerminal()) {
+                            terminated = true;
+                        }
+                    } else {
+                        if (statement instanceof VarNode) {
+                            newStatements.add(((VarNode)statement).setInit(null));
+                        }
+                    }
+                }
+                return newStatements;
+            }
+        });
+    }
+
+    @Override
+    public boolean enterBlock(final Block block) {
+        final LexicalContext lc = getLexicalContext();
+        if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) {
+            new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+        }
+        return true;
     }
 
     @Override
-    public Node enterBlock(final Block block) {
-        final Node       savedLastStatement = lastStatement;
-        final List<Node> savedStatements    = statements;
-        lexicalContext.push(block);
-        try {
-            this.statements = new ArrayList<>();
-            NodeVisitor visitor = this;
-            for (final Node statement : block.getStatements()) {
-                statement.accept(visitor);
-                /*
-                 * This is slightly unsound, for example if we have a loop with
-                 * a guarded statement like if (x) continue in the body and the
-                 * body ends with TERMINAL, e.g. return; we removed the continue
-                 * before we had the loop stack, as all we cared about was a
-                 * return last in the loop.
-                 *
-                 * @see NASHORN-285
-                 */
-                if (lastStatement != null && lastStatement.isTerminal()) {
-                    copyTerminal(block, lastStatement);
-                    visitor = new DeadCodeVarDeclarationVisitor();
-                }
-            }
-            block.setStatements(statements);
+    public Node leaveBlock(final Block block) {
+        //now we have committed the entire statement list to the block, but we need to truncate
+        //whatever is after the last terminal. block append won't append past it
+
+        final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext();
+
+        Node last = lc.getLastStatement();
 
-        } finally {
-            this.statements = savedStatements;
-            this.lastStatement = savedLastStatement;
-            lexicalContext.pop(block);
+        if (lc.isFunctionBody()) {
+            final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+            final boolean isProgram = currentFunction.isProgram();
+            final ReturnNode returnNode = new ReturnNode(
+                currentFunction.getSource(),
+                currentFunction.getToken(),
+                currentFunction.getFinish(),
+                isProgram ?
+                    compilerConstant(RETURN) :
+                    LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
+
+            last = returnNode.accept(this);
         }
 
-        return null;
+        if (last != null && last.isTerminal()) {
+            return block.setIsTerminal(lc, true);
+        }
+
+        return block;
     }
 
     @Override
-    public Node enterBreakNode(final BreakNode breakNode) {
-        return enterBreakOrContinue(breakNode);
+    public boolean enterBreakNode(final BreakNode breakNode) {
+        addStatement(breakNode);
+        return false;
     }
 
     @Override
-    public Node enterCallNode(final CallNode callNode) {
-        final Node function = markerFunction(callNode.getFunction());
-        callNode.setFunction(function);
-        checkEval(callNode); //check if this is an eval call and store the information
-        return callNode;
-    }
-
-    @Override
-    public Node leaveCaseNode(final CaseNode caseNode) {
-        caseNode.copyTerminalFlags(caseNode.getBody());
-        return caseNode;
+    public Node leaveCallNode(final CallNode callNode) {
+        return checkEval(callNode.setFunction(markerFunction(callNode.getFunction())));
     }
 
     @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
-        catchNode.copyTerminalFlags(catchNode.getBody());
-        addStatement(catchNode);
-        return catchNode;
-    }
-
-    @Override
-    public Node enterContinueNode(final ContinueNode continueNode) {
-        return enterBreakOrContinue(continueNode);
+        return addStatement(catchNode);
     }
 
     @Override
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        return enterWhileNode(doWhileNode);
+    public boolean enterContinueNode(final ContinueNode continueNode) {
+        addStatement(continueNode);
+        return false;
     }
 
     @Override
-    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
-        return leaveWhileNode(doWhileNode);
-    }
-
-    @Override
-    public Node enterEmptyNode(final EmptyNode emptyNode) {
-        return null;
+    public boolean enterEmptyNode(final EmptyNode emptyNode) {
+        return false;
     }
 
     @Override
     public Node leaveExecuteNode(final ExecuteNode executeNode) {
         final Node expr = executeNode.getExpression();
+        ExecuteNode node = executeNode;
 
-        if (getCurrentFunctionNode().isProgram()) {
+        final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+
+        if (currentFunction.isProgram()) {
             if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
                 if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
-                    executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN),
-                            getCurrentFunctionNode().getResultNode(),
-                            expr));
+                    node = executeNode.setExpression(
+                        new BinaryNode(
+                            executeNode.getSource(),
+                            Token.recast(
+                                executeNode.getToken(),
+                                TokenType.ASSIGN),
+                            compilerConstant(RETURN),
+                        expr));
                 }
             }
         }
 
-        copyTerminal(executeNode, executeNode.getExpression());
-        addStatement(executeNode);
-
-        return executeNode;
-    }
-
-    @Override
-    public Node enterForNode(final ForNode forNode) {
-        nest(forNode);
-        return forNode;
+        return addStatement(node);
     }
 
     @Override
     public Node leaveForNode(final ForNode forNode) {
-        final Node  test = forNode.getTest();
-        final Block body = forNode.getBody();
+        ForNode newForNode = forNode;
 
-        if (!forNode.isForIn() && test == null) {
-            setHasGoto(forNode);
-        }
-
-        final boolean escapes = controlFlowEscapes(body);
-        if (escapes) {
-            setTerminal(body, false);
+        final Node  test = forNode.getTest();
+        if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
+            newForNode = forNode.setTest(getLexicalContext(), null);
         }
 
-        // pop the loop from the loop context
-        unnest(forNode);
-
-        if (!forNode.isForIn() && conservativeAlwaysTrue(test)) {
-            forNode.setTest(null);
-            setHasGoto(forNode);
-            setTerminal(forNode, !escapes);
-        }
-
-        addStatement(forNode);
-
-        return forNode;
+        return addStatement(checkEscape(newForNode));
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        LOG.info("START FunctionNode: " + functionNode.getName());
-
-        if (functionNode.isLazy()) {
-            LOG.info("LAZY: " + functionNode.getName());
-            return null;
-        }
-        lexicalContext.push(functionNode);
-        initFunctionNode(functionNode);
-
-        nest(functionNode);
-
-        /*
-         * As we are evaluating a nested structure, we need to store the
-         * statement list for the surrounding block and restore it when the
-         * function is done
-         */
-        final List<Node> savedStatements = statements;
-        final Node savedLastStatement = lastStatement;
-
-        statements    = new ArrayList<>();
-        lastStatement = null;
-
-        if (functionNode.needsSelfSymbol()) {
-            //function needs to start with var funcIdent = __callee_;
-            statements.add(functionNode.getSelfSymbolInit().accept(this));
-        }
-
-        NodeVisitor visitor = this;
-        try {
-            //do the statements - this fills the block with code
-            boolean needsInitialEvalResult = functionNode.isProgram();
-            for (final Node statement : functionNode.getStatements()) {
-                // If this function is a program, then insert an assignment to the initial eval result after all
-                // function declarations.
-                if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) {
-                    addInitialEvalResult(functionNode);
-                    needsInitialEvalResult = false;
-                }
-                statement.accept(visitor);
-                //If there are unused terminated endpoints in the function, we need
-                // to add a "return undefined" in those places for correct semantics
-                LOG.info("Checking lastStatement="+lastStatement+" for terminal flags");
-                if (lastStatement != null && lastStatement.hasTerminalFlags()) {
-                    copyTerminal(functionNode, lastStatement);
-                    assert !needsInitialEvalResult;
-                    visitor = new DeadCodeVarDeclarationVisitor();
-                }
-            }
-            if(needsInitialEvalResult) {
-                addInitialEvalResult(functionNode);
-            }
-            functionNode.setStatements(statements);
-
-            if (!functionNode.isTerminal()) {
-                guaranteeReturn(functionNode);
-            }
-        } finally {
-            statements    = savedStatements;
-            lastStatement = savedLastStatement;
-        }
-
-        LOG.info("END FunctionNode: " + functionNode.getName());
-        unnest(functionNode);
-        lexicalContext.pop(functionNode);
-
-        functionNode.setState(CompilationState.LOWERED);
-
-        return null;
-    }
-
-    /**
-     * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the
-     * var declarations in them still have the effect of declaring a local variable on the function level. Therefore,
-     * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their
-     * initializers are wiped out as those are, in fact, dead code.
-     */
-    private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor {
-        DeadCodeVarDeclarationVisitor() {
-        }
-
-        @Override
-        public Node enterVarNode(VarNode varNode) {
-            // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was
-            // encountered, and all function declarations precede any terminal statements.
-            assert !varNode.isFunctionDeclaration();
-            if(varNode.getInit() == null) {
-                // No initializer, just pass it to Lower.
-                return varNode.accept(Lower.this);
-            }
-            // Wipe out the initializer and then pass it to Lower.
-            return varNode.setInit(null).accept(Lower.this);
-        }
-    }
-
-    private void addInitialEvalResult(final FunctionNode functionNode) {
-        new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(),
-                getInitialEvalResult(functionNode)).accept(this);
-    }
-
-    /**
-     * Result of initial result of evaluating a particular program, which is either the last function it declares, or
-     * undefined if it doesn't declare any functions.
-     * @param program
-     * @return the initial result of evaluating the program
-     */
-    private static Node getInitialEvalResult(final FunctionNode program) {
-        IdentNode lastFnName = null;
-        for (final FunctionNode fn : program.getDeclaredFunctions()) {
-            assert fn.isDeclared();
-            final IdentNode fnName = fn.getIdent();
-            if(fnName != null) {
-                lastFnName = fnName;
-            }
-        }
-        return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED);
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        return !functionNode.isLazy();
     }
 
     @Override
-    public Node enterIfNode(final IfNode ifNode) {
-        return nest(ifNode);
+    public Node leaveFunctionNode(final FunctionNode functionNode) {
+        LOG.info("END FunctionNode: ", functionNode.getName());
+        return functionNode.setState(getLexicalContext(), CompilationState.LOWERED);
     }
 
     @Override
     public Node leaveIfNode(final IfNode ifNode) {
-        final Node pass = ifNode.getPass();
-        final Node fail = ifNode.getFail();
-
-        if (pass.isTerminal() && fail != null && fail.isTerminal()) {
-            setTerminal(ifNode,  true);
-        }
-
-        addStatement(ifNode);
-        unnest(ifNode);
-
-        return ifNode;
-    }
-
-    @Override
-    public Node enterLabelNode(LabelNode labelNode) {
-        final Block body = labelNode.getBody();
-        body.accept(this);
-        copyTerminal(labelNode, body);
-        addStatement(labelNode);
-        return null;
-    }
-
-    @Override
-    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        addStatement(lineNumberNode, false); // don't put it in lastStatement cache
-        return null;
+        return addStatement(ifNode);
     }
 
     @Override
-    public Node enterReturnNode(final ReturnNode returnNode) {
-        final TryNode tryNode = returnNode.getTryChain();
-        final Node    expr    = returnNode.getExpression();
-
-        if (tryNode != null) {
-            //we are inside a try block - we don't necessarily have a result node yet. attr will do that.
-            if (expr != null) {
-                final Source source = getCurrentFunctionNode().getSource();
-
-                //we need to evaluate the result of the return in case it is complex while
-                //still in the try block, store it in a result value and return it afterwards
-                final long token        = returnNode.getToken();
-                final Node resultNode   = new IdentNode(getCurrentFunctionNode().getResultNode());
-                final Node assignResult = new BinaryNode(source, Token.recast(token, TokenType.ASSIGN), resultNode, expr);
-
-                //add return_in_try = expr; to try block
-                new ExecuteNode(source, token, Token.descPosition(token), assignResult).accept(this);
+    public Node leaveLabelNode(final LabelNode labelNode) {
+        return addStatement(labelNode);
+    }
 
-                //splice in the finally code, inlining it here
-                if (copyFinally(tryNode, null)) {
-                    return null;
-                }
-
-                //make sure that the return node now returns 'return_in_try'
-                returnNode.setExpression(resultNode);
-            } else if (copyFinally(tryNode, null)) {
-                return null;
-            }
-        } else if (expr != null) {
-            returnNode.setExpression(expr.accept(this));
-        }
-
-        addStatement(returnNode);
-
-        return null;
+    @Override
+    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
+        addStatement(lineNumberNode); // don't put it in lastStatement cache
+        return false;
     }
 
     @Override
@@ -448,31 +251,10 @@
         return returnNode;
     }
 
-    @Override
-    public Node enterSwitchNode(final SwitchNode switchNode) {
-        nest(switchNode);
-        return switchNode;
-    }
 
     @Override
     public Node leaveSwitchNode(final SwitchNode switchNode) {
-        unnest(switchNode);
-
-        final List<CaseNode> cases       = switchNode.getCases();
-        final CaseNode       defaultCase = switchNode.getDefaultCase();
-
-        boolean allTerminal = !cases.isEmpty();
-        for (final CaseNode caseNode : switchNode.getCases()) {
-            allTerminal &= caseNode.isTerminal();
-        }
-
-        if (allTerminal && defaultCase != null && defaultCase.isTerminal()) {
-            setTerminal(switchNode, true);
-        }
-
-        addStatement(switchNode);
-
-        return switchNode;
+        return addStatement(switchNode);
     }
 
     @Override
@@ -481,208 +263,234 @@
         return throwNode;
     }
 
-    @Override
-    public Node enterTryNode(final TryNode tryNode) {
-        final Block  finallyBody = tryNode.getFinallyBody();
-        final long   token       = tryNode.getToken();
-        final int    finish      = tryNode.getFinish();
+    private static Node ensureUniqueLabelsIn(final Node node) {
+        return node.accept(new NodeVisitor() {
+           @Override
+           public Node leaveDefault(final Node labelledNode) {
+               return labelledNode.ensureUniqueLabels(getLexicalContext());
+           }
+        });
+    }
+
+    private static List<Node> copyFinally(final Block finallyBody) {
+        final List<Node> newStatements = new ArrayList<>();
+        for (final Node statement : finallyBody.getStatements()) {
+            newStatements.add(ensureUniqueLabelsIn(statement));
+            if (statement.hasTerminalFlags()) {
+                return newStatements;
+            }
+        }
+        return newStatements;
+    }
+
+    private Block catchAllBlock(final TryNode tryNode) {
+        final Source source = tryNode.getSource();
+        final long   token  = tryNode.getToken();
+        final int    finish = tryNode.getFinish();
+
+        final IdentNode exception = new IdentNode(source, token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all"));
+
+        final Block catchBody = new Block(source, token, finish, new ThrowNode(source, token, finish, new IdentNode(exception))).
+                setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal
+
+        final CatchNode catchAllNode  = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
+        final Block     catchAllBlock = new Block(source, token, finish, catchAllNode);
+
+        //catchallblock -> catchallnode (catchnode) -> exception -> throw
+
+        return (Block)catchAllBlock.accept(this); //not accepted. has to be accepted by lower
+    }
+
+    private IdentNode compilerConstant(final CompilerConstants cc) {
+        final FunctionNode functionNode = getLexicalContext().getCurrentFunction();
+        return new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName());
+    }
+
+    private static boolean isTerminal(final List<Node> statements) {
+        return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags();
+    }
+
+    /**
+     * Splice finally code into all endpoints of a trynode
+     * @param tryNode the try node
+     * @param list of rethrowing throw nodes from synthetic catch blocks
+     * @param finallyBody the code in the original finally block
+     * @return new try node after splicing finally code (same if nop)
+     */
+    private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) {
+        final Source source = tryNode.getSource();
+        final int    finish = tryNode.getFinish();
+
+        assert tryNode.getFinallyBody() == null;
+
+        final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() {
+            final List<Node> insideTry = new ArrayList<>();
 
-        nest(tryNode);
+            @Override
+            public boolean enterDefault(final Node node) {
+                insideTry.add(node);
+                return true;
+            }
+
+            @Override
+            public boolean enterFunctionNode(final FunctionNode functionNode) {
+                // do not enter function nodes - finally code should not be inlined into them
+                return false;
+            }
+
+            @Override
+            public Node leaveThrowNode(final ThrowNode throwNode) {
+                if (rethrows.contains(throwNode)) {
+                    final List<Node> newStatements = copyFinally(finallyBody);
+                    if (!isTerminal(newStatements)) {
+                        newStatements.add(throwNode);
+                    }
+                    return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements);
+                }
+                return throwNode;
+            }
+
+            @Override
+            public Node leaveBreakNode(final BreakNode breakNode) {
+                return copy(breakNode, Lower.this.getLexicalContext().getBreakable(breakNode.getLabel()));
+            }
+
+            @Override
+            public Node leaveContinueNode(final ContinueNode continueNode) {
+                return copy(continueNode, Lower.this.getLexicalContext().getContinueTo(continueNode.getLabel()));
+            }
 
-        if (finallyBody == null) {
-            //do nothing if no finally exists
-            return tryNode;
+            @Override
+            public Node leaveReturnNode(final ReturnNode returnNode) {
+                final Node  expr  = returnNode.getExpression();
+                final List<Node> newStatements = new ArrayList<>();
+
+                final Node resultNode;
+                if (expr != null) {
+                    //we need to evaluate the result of the return in case it is complex while
+                    //still in the try block, store it in a result value and return it afterwards
+                    resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
+                    newStatements.add(new ExecuteNode(new BinaryNode(source, Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+                } else {
+                    resultNode = null;
+                }
+
+                newStatements.addAll(copyFinally(finallyBody));
+                if (!isTerminal(newStatements)) {
+                    newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
+                }
+
+                return new ExecuteNode(new Block(source, returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements));
+            }
+
+            private Node copy(final Node endpoint, final Node targetNode) {
+                if (!insideTry.contains(targetNode)) {
+                    final List<Node> newStatements = copyFinally(finallyBody);
+                    if (!isTerminal(newStatements)) {
+                        newStatements.add(endpoint);
+                    }
+                    return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements));
+                }
+                return endpoint;
+            }
+        });
+
+        addStatement(newTryNode);
+        for (final Node statement : finallyBody.getStatements()) {
+            addStatement(statement);
         }
 
-        /*
-         * We have a finally clause.
-         *
-         * Transform to do finally tail duplication as follows:
-         *
-         * <pre>
-         *  try {
-         *    try_body
-         *  } catch e1 {
-         *    catchbody_1
-         *  }
-         *  ...
-         *  } catch en {
-         *    catchbody_n
-         *  } finally {
-         *    finally_body
-         *  }
-         *
-         *  (where e1 ... en are optional)
-         *
-         *  turns into
-         *
-         *  try {
-         *    try {
-         *      try_body
-         *    } catch e1 {
-         *      catchbody1
-         *      //nothing inlined explicitly here, return, break other
-         *      //terminals may inline the finally body
-         *      ...
-         *    } catch en {
-         *      catchbody2
-         *      //nothing inlined explicitly here, return, break other
-         *      //terminals may inline the finally body
-         *    }
-         *  } catch all ex {
-         *      finally_body_inlined
-         *      rethrow ex
-         *  }
-         *  finally_body_inlined
-         * </pre>
-         *
-         * If tries are catches are terminal, visitors for return, break &
-         * continue will handle the tail duplications. Throw needs to be
-         * treated specially with the catchall as described in the above
-         * ASCII art.
-         *
-         * If the try isn't terminal we do the finally_body_inlined at the
-         * end. If the try is terminated with continue/break/return the
-         * existing visitor logic will inline the finally before that
-         * operation. if the try is terminated with a throw, the catches e1
-         * ... en will have a chance to process the exception. If the
-         * appropriate catch e1..en is non terminal we fall through to the
-         * last finally_body_inlined. if the catch e1...en IS terminal with
-         * continue/break/return existing visitor logic will fix it. If they
-         * are terminal with another throw it goes to the catchall and the
-         * finally_body_inlined marked (*) will fix it before rethrowing
-         * whatever problem there was for identical semantic.
-         */
-        final Source source = getCurrentFunctionNode().getSource();
-
-        // if try node does not contain a catch we can skip creation of a new
-        // try node and just append our synthetic catch to the existing try node.
-        if (!tryNode.getCatchBlocks().isEmpty()) {
-            // insert an intermediate try-catch* node, where we move the body and all catch blocks.
-            // the original try node become a try-finally container for the new try-catch* node.
-            // because we don't clone (to avoid deep copy), we have to fix the block chain in the end.
-            final TryNode innerTryNode;
-            innerTryNode = new TryNode(source, token, finish, tryNode.getNext());
-            innerTryNode.setBody(tryNode.getBody());
-            innerTryNode.setCatchBlocks(tryNode.getCatchBlocks());
-
-            // set outer tryNode's body to innerTryNode
-            final Block outerBody;
-            outerBody = new Block(source, token, finish);
-            outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
-            tryNode.setBody(outerBody);
-            tryNode.setCatchBlocks(null);
-        }
-
-        // create a catch-all that inlines finally and rethrows
-
-        final Block catchBlock      = new Block(source, token, finish);
-        //this catch block should get define symbol
-
-        final Block catchBody       = new Block(source, token, finish);
-        final Node  catchAllFinally = finallyBody.copy();
-
-        catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
-        setTerminal(catchBody, true);
-
-        final CatchNode catchAllNode;
-        final IdentNode exception;
-
-        exception    = new IdentNode(source, token, finish, getCurrentFunctionNode().uniqueName("catch_all"));
-        catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody);
-        catchAllNode.setIsSyntheticRethrow();
-
-        catchBlock.addStatement(catchAllNode);
-
-        // replace all catches of outer tryNode with the catch-all
-        tryNode.setCatchBlocks(new ArrayList<>(Arrays.asList(catchBlock)));
-
-        /*
-         * We leave the finally block for the original try in place for now
-         * so that children visitations will work. It is removed and placed
-         * afterwards in the else case below, after all children are visited
-         */
-
-        return tryNode;
+        return newTryNode;
     }
 
     @Override
     public Node leaveTryNode(final TryNode tryNode) {
-        final Block finallyBody   = tryNode.getFinallyBody();
+        final Block finallyBody = tryNode.getFinallyBody();
 
-        boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
-
-        for (final Block catchBlock : tryNode.getCatchBlocks()) {
-            allTerminal &= catchBlock.isTerminal();
+        if (finallyBody == null) {
+            return addStatement(tryNode);
         }
 
-        tryNode.setIsTerminal(allTerminal);
-
-        addStatement(tryNode);
-        unnest(tryNode);
+        /*
+         * create a new trynode
+         *    if we have catches:
+         *
+         *    try            try
+         *       x              try
+         *    catch               x
+         *       y              catch
+         *    finally z           y
+         *                   catchall
+         *                        rethrow
+         *
+         *   otheriwse
+         *
+         *   try              try
+         *      x               x
+         *   finally          catchall
+         *      y               rethrow
+         *
+         *
+         *   now splice in finally code wherever needed
+         *
+         */
+        TryNode newTryNode;
 
-        // if finally body is present, place it after the tryNode
-        if (finallyBody != null) {
-            tryNode.setFinallyBody(null);
-            addStatement(finallyBody);
+        final Block catchAll = catchAllBlock(tryNode);
+
+        final List<ThrowNode> rethrows = new ArrayList<>();
+        catchAll.accept(new NodeVisitor() {
+            @Override
+            public boolean enterThrowNode(final ThrowNode throwNode) {
+                rethrows.add(throwNode);
+                return true;
+            }
+        });
+        assert rethrows.size() == 1;
+
+        if (tryNode.getCatchBlocks().isEmpty()) {
+            newTryNode = tryNode.setFinallyBody(null);
+        } else {
+            Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Node>(Arrays.asList(tryNode.setFinallyBody(null))));
+            newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
         }
 
-        return tryNode;
+        newTryNode = newTryNode.setCatchBlocks(Arrays.asList(catchAll)).setFinallyBody(null);
+
+        /*
+         * Now that the transform is done, we have to go into the try and splice
+         * the finally block in front of any statement that is outside the try
+         */
+        return spliceFinally(newTryNode, rethrows, finallyBody);
     }
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
         addStatement(varNode);
+        if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) {
+            new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+        }
         return varNode;
     }
 
     @Override
-    public Node enterWhileNode(final WhileNode whileNode) {
-        return nest(whileNode);
-    }
-
-    @Override
     public Node leaveWhileNode(final WhileNode whileNode) {
         final Node test = whileNode.getTest();
-
-        if (test == null) {
-            setHasGoto(whileNode);
-        }
+        final Block body = whileNode.getBody();
 
-        final Block   body    = whileNode.getBody();
-        final boolean escapes = controlFlowEscapes(body);
-        if (escapes) {
-            setTerminal(body, false);
+        if (conservativeAlwaysTrue(test)) {
+            //turn it into a for node without a test.
+            final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this);
+            getLexicalContext().replace(whileNode, forNode);
+            return forNode;
         }
 
-        Node node = whileNode;
-
-        if (body.isTerminal()) {
-            if (whileNode instanceof DoWhileNode) {
-                setTerminal(whileNode, true);
-            } else if (conservativeAlwaysTrue(test)) {
-                node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish());
-                ((ForNode)node).setBody(body);
-                node.accept(this);
-                setTerminal(node, !escapes);
-            }
-        }
-
-        // pop the loop from the loop context
-        unnest(whileNode);
-        addStatement(node);
-
-        return node;
+         return addStatement(checkEscape(whileNode));
     }
 
     @Override
     public Node leaveWithNode(final WithNode withNode) {
-        if (withNode.getBody().isTerminal()) {
-            setTerminal(withNode,  true);
-        }
-        addStatement(withNode);
-
-        return withNode;
+        return addStatement(withNode);
     }
 
     @Override
@@ -741,23 +549,25 @@
      *
      * @param callNode call node to check if it's an eval
      */
-    private void checkEval(final CallNode callNode) {
+    private CallNode checkEval(final CallNode callNode) {
         if (callNode.getFunction() instanceof IdentNode) {
 
             final List<Node> args   = callNode.getArgs();
             final IdentNode  callee = (IdentNode)callNode.getFunction();
 
             // 'eval' call with at least one argument
-            if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
-                final CallNode.EvalArgs evalArgs =
+            if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
+                final FunctionNode currentFunction = getLexicalContext().getCurrentFunction();
+                return callNode.setEvalArgs(
                     new CallNode.EvalArgs(
-                        args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
-                        getCurrentFunctionNode().getThisNode(),
+                        ensureUniqueLabelsIn(args.get(0)).accept(this),
+                        compilerConstant(THIS),
                         evalLocation(callee),
-                        getCurrentFunctionNode().isStrictMode());
-                callNode.setEvalArgs(evalArgs);
+                        currentFunction.isStrict()));
             }
         }
+
+        return callNode;
     }
 
     private static boolean conservativeAlwaysTrue(final Node node) {
@@ -773,7 +583,7 @@
      * @param loopBody the loop body to check
      * @return true if control flow may escape the loop
      */
-    private boolean controlFlowEscapes(final Node loopBody) {
+    private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) {
         final List<Node> escapes = new ArrayList<>();
 
         loopBody.accept(new NodeVisitor() {
@@ -786,7 +596,7 @@
             @Override
             public Node leaveContinueNode(final ContinueNode node) {
                 // all inner loops have been popped.
-                if (nesting.contains(node.getTargetNode())) {
+                if (lex.contains(lex.getContinueTo(node.getLabel()))) {
                     escapes.add(node);
                 }
                 return node;
@@ -796,136 +606,24 @@
         return !escapes.isEmpty();
     }
 
-    private void guaranteeReturn(final FunctionNode functionNode) {
-        Node resultNode;
-
-        if (functionNode.isProgram()) {
-            resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
-        } else {
-            if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
-                return; //already in place or not needed, as it should be for a non-undefined returning function
-            }
-            resultNode = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
+    private LoopNode checkEscape(final LoopNode loopNode) {
+        final LexicalContext lc = getLexicalContext();
+        final boolean escapes = controlFlowEscapes(lc, loopNode.getBody());
+        if (escapes) {
+            return loopNode.
+                setBody(lc, loopNode.getBody().setIsTerminal(lc, false)).
+                setControlFlowEscapes(lc, escapes);
         }
-
-        //create a return statement
-        final Node returnNode = new ReturnNode(functionNode.getSource(), functionNode.getLastToken(), functionNode.getFinish(), resultNode, null);
-        returnNode.accept(this);
+        return loopNode;
     }
 
 
-    private Node nest(final Node node) {
-        LOG.info("Nesting: " + node);
-        LOG.indent();
-        nesting.push(node);
-        return node;
-    }
-
-    private void unnest(final Node node) {
-        LOG.unindent();
-        assert nesting.getFirst() == node : "inconsistent nesting order : " + nesting.getFirst() + " != " + node;
-        LOG.info("Unnesting: " + nesting);
-        nesting.pop();
-    }
-
-    private static void setTerminal(final Node node, final boolean isTerminal) {
-        LOG.info("terminal = " + isTerminal + " for " + node);
-        node.setIsTerminal(isTerminal);
-    }
-
-    private static void setHasGoto(final Node node) { //, final boolean hasGoto) {
-        LOG.info("hasGoto = true for " + node);
-        node.setHasGoto();
-    }
-
-    private static void copyTerminal(final Node node, final Node sourceNode) {
-        LOG.info("copy terminal flags " + sourceNode + " -> " + node);
-        node.copyTerminalFlags(sourceNode);
-    }
-
-    private void addStatement(final Node statement, final boolean storeInLastStatement) {
-        LOG.info("add statement = " + statement + " (lastStatement = " + lastStatement + ")");
-        statements.add(statement);
-        if (storeInLastStatement) {
-            lastStatement = statement;
-        }
-    }
-
-    private void addStatement(final Node statement) {
-        addStatement(statement, true);
+    private Node addStatement(final Node statement) {
+        ((BlockLexicalContext)getLexicalContext()).appendStatement(statement);
+        return statement;
     }
 
     /**
-     * Determine if Try block is inside target block.
-     *
-     * @param tryNode Try node to test.
-     * @param target  Target block.
-     *
-     * @return true if try block is inside the target, false otherwise.
-     */
-    private boolean isNestedTry(final TryNode tryNode, final Block target) {
-        for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) {
-            final Block block = blocks.next();
-            if(block == target) {
-                return false;
-            }
-            if(tryNode.isChildBlock(block)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Clones the body of the try finallys up to the target block.
-     *
-     * @param node       first try node in the chain.
-     * @param targetNode target block of the break/continue statement or null for return
-     *
-     * @return true if terminates.
-     */
-    private boolean copyFinally(final TryNode node, final Node targetNode) {
-        Block target = null;
-
-        if (targetNode instanceof Block) {
-            target = (Block)targetNode;
-        }
-
-        for (TryNode tryNode = node; tryNode != null; tryNode = tryNode.getNext()) {
-            if (target != null && !isNestedTry(tryNode, target)) {
-                return false;
-            }
-
-            Block finallyBody = tryNode.getFinallyBody();
-            if (finallyBody == null) {
-                continue;
-            }
-
-            finallyBody = (Block)finallyBody.copy();
-            final boolean hasTerminalFlags = finallyBody.hasTerminalFlags();
-
-            new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this);
-
-            if (hasTerminalFlags) {
-                getCurrentBlock().copyTerminalFlags(finallyBody);
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    private Node enterBreakOrContinue(final LabeledNode labeledNode) {
-        final TryNode tryNode = labeledNode.getTryChain();
-        if (tryNode != null && copyFinally(tryNode, labeledNode.getTargetNode())) {
-            return null;
-        }
-        addStatement(labeledNode);
-        return null;
-    }
-
-
-    /**
      * An internal expression has a symbol that is tagged internal. Check if
      * this is such a node
      *
@@ -939,40 +637,21 @@
 
     /**
      * Is this an assignment to the special variable that hosts scripting eval
-     * results?
+     * results, i.e. __return__?
      *
      * @param expression expression to check whether it is $evalresult = X
      * @return true if an assignment to eval result, false otherwise
      */
-    private boolean isEvalResultAssignment(final Node expression) {
+    private static boolean isEvalResultAssignment(final Node expression) {
         Node e = expression;
-        if (e.tokenType() == TokenType.DISCARD) {
-            e = ((UnaryNode)expression).rhs();
-        }
-        final Node resultNode = getCurrentFunctionNode().getResultNode();
-        return e instanceof BinaryNode && ((BinaryNode)e).lhs().equals(resultNode);
-    }
-
-    /**
-     * Prepare special function nodes.
-     * TODO : only create those that are needed.
-     * TODO : make sure slot numbering is not hardcoded in {@link CompilerConstants} - now creation order is significant
-     */
-    private static void initFunctionNode(final FunctionNode functionNode) {
-        final Source source = functionNode.getSource();
-        final long token    = functionNode.getToken();
-        final int  finish   = functionNode.getFinish();
-
-        functionNode.setThisNode(new IdentNode(source, token, finish, THIS.tag()));
-        functionNode.setScopeNode(new IdentNode(source, token, finish, SCOPE.tag()));
-        functionNode.setResultNode(new IdentNode(source, token, finish, SCRIPT_RETURN.tag()));
-        functionNode.setCalleeNode(new IdentNode(source, token, finish, CALLEE.tag()));
-        if (functionNode.isVarArg()) {
-            functionNode.setVarArgsNode(new IdentNode(source, token, finish, VARARGS.tag()));
-            if (functionNode.needsArguments()) {
-                functionNode.setArgumentsNode(new IdentNode(source, token, finish, ARGUMENTS.tag()));
+        assert e.tokenType() != TokenType.DISCARD; //there are no discards this early anymore
+        if (e instanceof BinaryNode) {
+            final Node lhs = ((BinaryNode)e).lhs();
+            if (lhs instanceof IdentNode) {
+                return ((IdentNode)lhs).getName().equals(RETURN.symbolName());
             }
         }
+        return false;
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu May 16 11:47:51 2013 +0100
@@ -53,9 +53,12 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER;
+import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
@@ -67,6 +70,7 @@
 import java.util.ArrayDeque;
 import java.util.EnumSet;
 import java.util.Iterator;
+import java.util.List;
 import jdk.internal.dynalink.support.NameCodec;
 import jdk.internal.org.objectweb.asm.Handle;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
@@ -79,14 +83,14 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
-import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.runtime.ArgumentSetter;
+import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.JSType;
-import jdk.nashorn.internal.runtime.Scope;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -116,10 +120,10 @@
     private final ClassEmitter classEmitter;
 
     /** FunctionNode representing this method, or null if none exists */
-    private FunctionNode functionNode;
+    protected FunctionNode functionNode;
 
-    /** SplitNode representing the current split, or null if none exists */
-    private SplitNode splitNode;
+    /** Check whether this emitter ever has a function return point */
+    private boolean hasReturn;
 
     /** The script environment */
     private final ScriptEnvironment env;
@@ -203,7 +207,7 @@
 
     @Override
     public String toString() {
-        return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + stack;
+        return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this);
     }
 
     /**
@@ -476,8 +480,8 @@
 
         String name = symbol.getName();
 
-        if (name.equals(THIS.tag())) {
-            name = THIS_DEBUGGER.tag();
+        if (name.equals(THIS.symbolName())) {
+            name = THIS_DEBUGGER.symbolName();
         }
 
         method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot());
@@ -654,7 +658,7 @@
      * @return this method emitter
      */
     MethodEmitter loadConstants() {
-        getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor());
+        getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor());
         assert peekType().isArray() : peekType();
         return this;
     }
@@ -669,7 +673,7 @@
      * @return the method emitter
      */
     MethodEmitter loadUndefined(final Type type) {
-        debug("load undefined " + type);
+        debug("load undefined ", type);
         pushType(type.loadUndefined(method));
         return this;
     }
@@ -681,7 +685,7 @@
      * @return the method emitter
      */
     MethodEmitter loadEmpty(final Type type) {
-        debug("load empty " + type);
+        debug("load empty ", type);
         pushType(type.loadEmpty(method));
         return this;
     }
@@ -814,7 +818,7 @@
     }
 
     /**
-     * Push an local variable to the stack. If the symbol representing
+     * Push a local variable to the stack. If the symbol representing
      * the local variable doesn't have a slot, this is a NOP
      *
      * @param symbol the symbol representing the local variable.
@@ -835,13 +839,13 @@
             if (functionNode.needsArguments()) {
                 // ScriptObject.getArgument(int) on arguments
                 debug("load symbol", symbol.getName(), " arguments index=", index);
-                loadArguments();
+                loadCompilerConstant(ARGUMENTS);
                 load(index);
                 ScriptObject.GET_ARGUMENT.invoke(this);
             } else {
                 // array load from __varargs__
                 debug("load symbol", symbol.getName(), " array index=", index);
-                loadVarArgs();
+                loadCompilerConstant(VARARGS);
                 load(symbol.getFieldIndex());
                 arrayload();
             }
@@ -870,48 +874,13 @@
         if(functionNode == null) {
             return slot == CompilerConstants.JAVA_THIS.slot();
         }
-        final int thisSlot = functionNode.getThisNode().getSymbol().getSlot();
+        final int thisSlot = compilerConstant(THIS).getSlot();
         assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1
         assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0
         return slot == thisSlot;
     }
 
     /**
-     * Push the this object to the stack.
-     *
-     * @return the method emitter
-     */
-    MethodEmitter loadThis() {
-        load(functionNode.getThisNode().getSymbol());
-        return this;
-    }
-
-    /**
-     * Push the scope object to the stack.
-     *
-     * @return the method emitter
-     */
-    MethodEmitter loadScope() {
-        if (peekType() == Type.SCOPE) {
-            dup();
-            return this;
-        }
-        load(functionNode.getScopeNode().getSymbol());
-        return this;
-    }
-
-    /**
-     * Push the return object to the stack.
-     *
-     * @return the method emitter
-     */
-    MethodEmitter loadResult() {
-        load(functionNode.getResultNode().getSymbol());
-        return this;
-    }
-
-
-    /**
      * Push a method handle to the stack
      *
      * @param className  class name
@@ -927,62 +896,33 @@
         return this;
     }
 
-    /**
-     * Push the varargs object to the stack
-     *
-     * @return the method emitter
-     */
-    MethodEmitter loadVarArgs() {
-        debug("load var args " + functionNode.getVarArgsNode().getSymbol());
-        return load(functionNode.getVarArgsNode().getSymbol());
-    }
-
-    /**
-     * Push the arguments array to the stack
-     *
-     * @return the method emitter
-     */
-    MethodEmitter loadArguments() {
-        debug("load arguments ", functionNode.getArgumentsNode().getSymbol());
-        assert functionNode.getArgumentsNode().getSymbol().getSlot() != 0;
-        return load(functionNode.getArgumentsNode().getSymbol());
+    private Symbol compilerConstant(final CompilerConstants cc) {
+        return functionNode.getBody().getExistingSymbol(cc.symbolName());
     }
 
     /**
-     * Push the callee object to the stack
-     *
-     * @return the method emitter
+     * True if this method has a slot allocated for the scope variable (meaning, something in the method actually needs
+     * the scope).
+     * @return if this method has a slot allocated for the scope variable.
      */
-    MethodEmitter loadCallee() {
-        final Symbol calleeSymbol = functionNode.getCalleeNode().getSymbol();
-        debug("load callee ", calleeSymbol);
-        assert calleeSymbol.getSlot() == 0 : "callee has wrong slot " + calleeSymbol.getSlot() + " in " + functionNode.getName();
-
-        return load(calleeSymbol);
+    boolean hasScope() {
+        return compilerConstant(SCOPE).hasSlot();
     }
 
-    /**
-     * Pop the scope from the stack and store it in its predefined slot
-     */
-    void storeScope() {
-        debug("store scope");
-        store(functionNode.getScopeNode().getSymbol());
+    MethodEmitter loadCompilerConstant(final CompilerConstants cc) {
+        final Symbol symbol = compilerConstant(cc);
+        if (cc == SCOPE && peekType() == Type.SCOPE) {
+            dup();
+            return this;
+        }
+        debug("load compiler constant ", symbol);
+        return load(symbol);
     }
 
-    /**
-     * Pop the return from the stack and store it in its predefined slot
-     */
-    void storeResult() {
-        debug("store result");
-        store(functionNode.getResultNode().getSymbol());
-    }
-
-    /**
-     * Pop the arguments array from the stack and store it in its predefined slot
-     */
-    void storeArguments() {
-        debug("store arguments");
-        store(functionNode.getArgumentsNode().getSymbol());
+    void storeCompilerConstant(final CompilerConstants cc) {
+        final Symbol symbol = compilerConstant(cc);
+        debug("store compiler constant ", symbol);
+        store(symbol);
     }
 
     /**
@@ -1030,13 +970,13 @@
             final int index = symbol.getFieldIndex();
             if (functionNode.needsArguments()) {
                 debug("store symbol", symbol.getName(), " arguments index=", index);
-                loadArguments();
+                loadCompilerConstant(ARGUMENTS);
                 load(index);
                 ArgumentSetter.SET_ARGUMENT.invoke(this);
             } else {
                 // varargs without arguments object - just do array store to __varargs__
                 debug("store symbol", symbol.getName(), " array index=", index);
-                loadVarArgs();
+                loadCompilerConstant(VARARGS);
                 load(index);
                 ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this);
             }
@@ -1144,7 +1084,7 @@
      * @return the method emitter
      */
     MethodEmitter newarray(final ArrayType arrayType) {
-        debug("newarray ", "arrayType=" + arrayType);
+        debug("newarray ", "arrayType=", arrayType);
         popType(Type.INT); //LENGTH
         pushType(arrayType.newarray(method));
         return this;
@@ -1223,7 +1163,7 @@
      * @return the method emitter
      */
     MethodEmitter invokespecial(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokespecial", className + "." + methodName + methodDescriptor);
+        debug("invokespecial", className, ".", methodName, methodDescriptor);
         return invoke(INVOKESPECIAL, className, methodName, methodDescriptor, true);
     }
 
@@ -1237,7 +1177,7 @@
      * @return the method emitter
      */
     MethodEmitter invokevirtual(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokevirtual", className + "." + methodName + methodDescriptor + " " + stack);
+        debug("invokevirtual", className, ".", methodName, methodDescriptor, " ", stack);
         return invoke(INVOKEVIRTUAL, className, methodName, methodDescriptor, true);
     }
 
@@ -1251,7 +1191,7 @@
      * @return the method emitter
      */
     MethodEmitter invokestatic(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokestatic", className + "." + methodName + methodDescriptor);
+        debug("invokestatic", className, ".", methodName, methodDescriptor);
         invoke(INVOKESTATIC, className, methodName, methodDescriptor, false);
         return this;
     }
@@ -1284,7 +1224,7 @@
      * @return the method emitter
      */
     MethodEmitter invokeinterface(final String className, final String methodName, final String methodDescriptor) {
-        debug("invokeinterface", className + "." + methodName + methodDescriptor);
+        debug("invokeinterface", className, ".", methodName, methodDescriptor);
         return invoke(INVOKEINTERFACE, className, methodName, methodDescriptor, true);
     }
 
@@ -1336,15 +1276,20 @@
      */
     void conditionalJump(final Condition cond, final boolean isCmpG, final Label trueLabel) {
         if (peekType().isCategory2()) {
-            debug("[ld]cmp isCmpG=" + isCmpG);
+            debug("[ld]cmp isCmpG=", isCmpG);
             pushType(get2n().cmp(method, isCmpG));
             jump(Condition.toUnary(cond), trueLabel, 1);
         } else {
-            debug("if" + cond);
+            debug("if", cond);
             jump(Condition.toBinary(cond, peekType().isObject()), trueLabel, 2);
         }
     }
 
+    MethodEmitter registerReturn() {
+        this.hasReturn = true;
+        return this;
+    }
+
     /**
      * Perform a non void return, popping the type from the stack
      *
@@ -1385,22 +1330,7 @@
      *
      * @param label destination label
      */
-    void splitAwareGoto(final Label label) {
-
-        if (splitNode != null) {
-            final int index = splitNode.getExternalTargets().indexOf(label);
-
-            if (index > -1) {
-                loadScope();
-                checkcast(Scope.class);
-                load(index + 1);
-                invoke(Scope.SET_SPLIT_STATE);
-                loadUndefined(Type.OBJECT);
-                _return(functionNode.getReturnType());
-                return;
-            }
-        }
-
+    void splitAwareGoto(final LexicalContext lc, final Label label) {
         _goto(label);
     }
 
@@ -1595,7 +1525,7 @@
      */
     private void mergeStackTo(final Label label) {
         final ArrayDeque<Type> labelStack = label.getStack();
-        //debug(labelStack == null ? " >> Control flow - first visit " + label : " >> Control flow - JOIN with " + labelStack + " at " + label);
+        //debug(labelStack == null ? " >> Control flow - first visit ", label : " >> Control flow - JOIN with ", labelStack, " at ", label);
         if (labelStack == null) {
             assert stack != null;
             label.setStack(stack.clone());
@@ -1788,7 +1718,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicNew(final int argCount, final int flags) {
-        debug("dynamic_new", "argcount=" + argCount);
+        debug("dynamic_new", "argcount=", argCount);
         final String signature = getDynamicSignature(Type.OBJECT, argCount);
         method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
         pushType(Type.OBJECT); //TODO fix result type
@@ -1805,7 +1735,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
-        debug("dynamic_call", "args=" + argCount, "returnType=" + returnType);
+        debug("dynamic_call", "args=", argCount, "returnType=", returnType);
         final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
         debug("   signature", signature);
         method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
@@ -1824,7 +1754,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
-        debug("dynamic_runtime_call", name, "args=" + request.getArity(), "returnType=" + returnType);
+        debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
         final String signature = getDynamicSignature(returnType, request.getArity());
         debug("   signature", signature);
         method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
@@ -1895,7 +1825,7 @@
      * @return the method emitter
      */
     MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
-        debug("dynamic_get_index", peekType(1) + "[" + peekType() + "]");
+        debug("dynamic_get_index", peekType(1), "[", peekType(), "]");
 
         Type resultType = result;
         if (result.isBoolean()) {
@@ -1931,7 +1861,7 @@
      * @param flags call site flags for setter
      */
     void dynamicSetIndex(final int flags) {
-        debug("dynamic_set_index", peekType(2) + "[" + peekType(1) + "] =", peekType());
+        debug("dynamic_set_index", peekType(2), "[", peekType(1), "] =", peekType());
 
         Type value = peekType();
         if (value.isObject() || value.isBoolean()) {
@@ -2031,7 +1961,7 @@
      * @return the method emitter
      */
     MethodEmitter getField(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("getfield", "receiver=" + peekType(), className + "." + fieldName + fieldDescriptor);
+        debug("getfield", "receiver=", peekType(), className, ".", fieldName, fieldDescriptor);
         final Type receiver = popType();
         assert receiver.isObject();
         method.visitFieldInsn(GETFIELD, className, fieldName, fieldDescriptor);
@@ -2049,7 +1979,7 @@
      * @return the method emitter
      */
     MethodEmitter getStatic(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("getstatic", className + "." + fieldName + "." + fieldDescriptor);
+        debug("getstatic", className, ".", fieldName, ".", fieldDescriptor);
         method.visitFieldInsn(GETSTATIC, className, fieldName, fieldDescriptor);
         pushType(fieldType(fieldDescriptor));
         return this;
@@ -2063,7 +1993,7 @@
      * @param fieldDescriptor field descriptor
      */
     void putField(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("putfield", "receiver=" + peekType(1), "value=" + peekType());
+        debug("putfield", "receiver=", peekType(1), "value=", peekType());
         popType(fieldType(fieldDescriptor));
         popType(Type.OBJECT);
         method.visitFieldInsn(PUTFIELD, className, fieldName, fieldDescriptor);
@@ -2077,7 +2007,7 @@
      * @param fieldDescriptor field descriptor
      */
     void putStatic(final String className, final String fieldName, final String fieldDescriptor) {
-        debug("putfield", "value=" + peekType());
+        debug("putfield", "value=", peekType());
         popType(fieldType(fieldDescriptor));
         method.visitFieldInsn(PUTSTATIC, className, fieldName, fieldDescriptor);
     }
@@ -2237,7 +2167,7 @@
             }
 
             if (env != null) { //early bootstrap code doesn't have inited context yet
-                LOG.info(sb.toString());
+                LOG.info(sb);
                 if (DEBUG_TRACE_LINE == linePrefix) {
                     new Throwable().printStackTrace(LOG.getOutputStream());
                 }
@@ -2254,21 +2184,12 @@
         this.functionNode = functionNode;
     }
 
-    /**
-     * Get the split node for this method emitter, if this is code
-     * generation due to splitting large methods
-     *
-     * @return split node
-     */
-    SplitNode getSplitNode() {
-        return splitNode;
+    boolean hasReturn() {
+        return hasReturn;
     }
 
-    /**
-     * Set the split node for this method emitter
-     * @param splitNode split node
-     */
-    void setSplitNode(final SplitNode splitNode) {
-        this.splitNode = splitNode;
+    List<Label> getExternalTargets() {
+        return null;
     }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java	Thu May 16 11:47:51 2013 +0100
@@ -53,7 +53,7 @@
      */
     public Namespace(final Namespace parent) {
         this.parent    = parent;
-        directory = new HashMap<>();
+        this.directory = new HashMap<>();
     }
 
     /**
@@ -65,10 +65,6 @@
         return parent;
     }
 
-    private HashMap<String, Integer> getDirectory() {
-        return directory;
-    }
-
     /**
      * Create a uniqueName name in the namespace in the form base$n where n varies
      * .
@@ -78,7 +74,7 @@
      */
     public String uniqueName(final String base) {
         for (Namespace namespace = this; namespace != null; namespace = namespace.getParent()) {
-            final HashMap<String, Integer> namespaceDirectory = namespace.getDirectory();
+            final HashMap<String, Integer> namespaceDirectory = namespace.directory;
             final Integer                  counter            = namespaceDirectory.get(base);
 
             if (counter != null) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu May 16 11:47:51 2013 +0100
@@ -28,10 +28,10 @@
 import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.ALLOCATE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_ARGUMENTS;
+import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_MAP;
 import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS;
 import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX;
-import static jdk.nashorn.internal.codegen.CompilerConstants.MAP;
 import static jdk.nashorn.internal.codegen.CompilerConstants.className;
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
@@ -204,8 +204,8 @@
      * @return The class name.
      */
     public static String getClassName(final int fieldCount) {
-        return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount :
-                                 SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag();
+        return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount :
+                                 SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName();
     }
 
     /**
@@ -218,7 +218,23 @@
      * @return The class name.
      */
     public static String getClassName(final int fieldCount, final int paramCount) {
-        return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount + SCOPE_MARKER + paramCount;
+        return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount + SCOPE_MARKER + paramCount;
+    }
+
+    /**
+     * Returns the number of fields in the JavaScript scope class. Its name had to be generated using either
+     * {@link #getClassName(int)} or {@link #getClassName(int, int)}.
+     * @param clazz the JavaScript scope class.
+     * @return the number of fields in the scope class.
+     */
+    public static int getFieldCount(Class<?> clazz) {
+        final String name = clazz.getSimpleName();
+        final String prefix = JS_OBJECT_PREFIX.symbolName();
+        if(prefix.equals(name)) {
+            return 0;
+        }
+        final int scopeMarker = name.indexOf(SCOPE_MARKER);
+        return Integer.parseInt(scopeMarker == -1 ? name.substring(prefix.length()) : name.substring(prefix.length(), scopeMarker));
     }
 
     /**
@@ -387,7 +403,7 @@
         final MethodEmitter init = classEmitter.init(PropertyMap.class);
         init.begin();
         init.load(Type.OBJECT, JAVA_THIS.slot());
-        init.load(Type.OBJECT, MAP.slot());
+        init.load(Type.OBJECT, INIT_MAP.slot());
         init.invoke(constructorNoLookup(ScriptObject.class, PropertyMap.class));
 
         return init;
@@ -402,7 +418,7 @@
         final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class);
         init.begin();
         init.load(Type.OBJECT, JAVA_THIS.slot());
-        init.load(Type.OBJECT, MAP.slot());
+        init.load(Type.OBJECT, INIT_MAP.slot());
         init.load(Type.OBJECT, INIT_SCOPE.slot());
         init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class));
 
@@ -418,7 +434,7 @@
         final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
         init.begin();
         init.load(Type.OBJECT, JAVA_THIS.slot());
-        init.load(Type.OBJECT, MAP.slot());
+        init.load(Type.OBJECT, INIT_MAP.slot());
         init.load(Type.OBJECT, INIT_SCOPE.slot());
         init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
         init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
@@ -449,7 +465,7 @@
      * @param className    Name of JavaScript class.
      */
     private static void newAllocate(final ClassEmitter classEmitter, final String className) {
-        final MethodEmitter allocate = classEmitter.method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), ALLOCATE.tag(), ScriptObject.class, PropertyMap.class);
+        final MethodEmitter allocate = classEmitter.method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), ALLOCATE.symbolName(), ScriptObject.class, PropertyMap.class);
         allocate.begin();
         allocate._new(className);
         allocate.dup();
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Thu May 16 11:47:51 2013 +0100
@@ -36,7 +36,7 @@
 public abstract class ObjectCreator {
 
     /** Compile unit for this ObjectCreator, see CompileUnit */
-    protected final CompileUnit   compileUnit;
+    //protected final CompileUnit   compileUnit;
 
     /** List of keys to initiate in this ObjectCreator */
     protected final List<String>  keys;
@@ -66,7 +66,6 @@
      */
     protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean hasArguments) {
         this.codegen       = codegen;
-        this.compileUnit   = codegen.getCurrentCompileUnit();
         this.keys          = keys;
         this.symbols       = symbols;
         this.isScope       = isScope;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
+
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.runtime.Scope;
+
+/**
+ * Emitter used for splitting methods. Needs to keep track of if there are jump targets
+ * outside the current split node. All external jump targets encountered at method
+ * emission are logged, and {@code CodeGenerator#leaveSplitNode(SplitNode)} creates
+ * an appropriate jump table when the SplitNode has been iterated through
+ */
+public class SplitMethodEmitter extends MethodEmitter {
+
+    private final SplitNode splitNode;
+
+    private final List<Label> externalTargets = new ArrayList<>();
+
+    SplitMethodEmitter(final ClassEmitter classEmitter, final MethodVisitor mv, SplitNode splitNode) {
+        super(classEmitter, mv);
+        this.splitNode = splitNode;
+    }
+
+    @Override
+    void splitAwareGoto(final LexicalContext lc, final Label label) {
+        assert splitNode != null;
+        final int index = findExternalTarget(lc, label);
+        if (index >= 0) {
+            loadCompilerConstant(SCOPE);
+            checkcast(Scope.class);
+            load(index + 1);
+            invoke(Scope.SET_SPLIT_STATE);
+            loadUndefined(Type.OBJECT);
+            _return(functionNode.getReturnType());
+            return;
+        }
+        super.splitAwareGoto(lc, label);
+    }
+
+    private int findExternalTarget(final LexicalContext lc, final Label label) {
+        final int index = externalTargets.indexOf(label);
+
+        if (index >= 0) {
+            return index;
+        }
+
+        if (lc.isExternalTarget(splitNode, label)) {
+             externalTargets.add(label);
+             return externalTargets.size() - 1;
+         }
+         return -1;
+    }
+
+    @Override
+    MethodEmitter registerReturn() {
+        super.registerReturn();
+        loadCompilerConstant(SCOPE);
+        checkcast(Scope.class);
+        load(0);
+        invoke(Scope.SET_SPLIT_STATE);
+        return this;
+    }
+
+    @Override
+    final List<Label> getExternalTargets() {
+        return externalTargets;
+    }
+}
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Thu May 16 11:47:51 2013 +0100
@@ -28,29 +28,18 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX;
 
 import java.util.ArrayList;
-import java.util.Deque;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
-import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
 import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.SplitNode;
-import jdk.nashorn.internal.ir.SwitchNode;
-import jdk.nashorn.internal.ir.WhileNode;
-import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.DebugLogger;
 import jdk.nashorn.internal.runtime.Source;
@@ -64,7 +53,7 @@
     private final Compiler compiler;
 
     /** IR to be broken down. */
-    private final FunctionNode functionNode;
+    private FunctionNode outermost;
 
     /** Compile unit for the main script. */
     private final CompileUnit outermostCompileUnit;
@@ -72,8 +61,6 @@
     /** Cache for calculated block weights. */
     private final Map<Node, Long> weightCache = new HashMap<>();
 
-    private final LexicalContext lexicalContext = new LexicalContext();
-
     /** Weight threshold for when to start a split. */
     public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
 
@@ -88,70 +75,92 @@
      */
     public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
         this.compiler             = compiler;
-        this.functionNode         = functionNode;
+        this.outermost = functionNode;
         this.outermostCompileUnit = outermostCompileUnit;
     }
 
     /**
      * Execute the split
      */
-    void split() {
+    FunctionNode split(final FunctionNode fn) {
+        FunctionNode functionNode = fn;
+
         if (functionNode.isLazy()) {
-            LOG.finest("Postponing split of '" + functionNode.getName() + "' as it's lazy");
-            return;
+            LOG.finest("Postponing split of '", functionNode.getName(), "' as it's lazy");
+            return functionNode;
         }
 
-        LOG.finest("Initiating split of '" + functionNode.getName() + "'");
+        LOG.finest("Initiating split of '", functionNode.getName(), "'");
+
+        final LexicalContext lc = getLexicalContext();
 
         long weight = WeighNodes.weigh(functionNode);
+        final boolean top = compiler.getFunctionNode() == outermost;
 
         if (weight >= SPLIT_THRESHOLD) {
-            LOG.finest("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD);
-
-            functionNode.accept(this);
+            LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD);
+            functionNode = (FunctionNode)functionNode.accept(this);
 
             if (functionNode.isSplit()) {
                 // Weight has changed so weigh again, this time using block weight cache
                 weight = WeighNodes.weigh(functionNode, weightCache);
+                functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(lc));
             }
 
             if (weight >= SPLIT_THRESHOLD) {
-                weight = splitBlock(functionNode, functionNode);
-            }
-
-            if (functionNode.isSplit()) {
-                functionNode.accept(new SplitFlowAnalyzer());
+                functionNode = functionNode.setBody(lc, splitBlock(functionNode.getBody(), functionNode));
+                weight = WeighNodes.weigh(functionNode.getBody(), weightCache);
             }
         }
 
-        assert functionNode.getCompileUnit() == null : "compile unit already set";
+        assert functionNode.getCompileUnit() == null : "compile unit already set for " + functionNode.getName();
 
-        if (compiler.getFunctionNode() == functionNode) { //functionNode.isScript()) {
+        if (top) {
             assert outermostCompileUnit != null : "outermost compile unit is null";
-
-            functionNode.setCompileUnit(outermostCompileUnit);
+            functionNode = functionNode.setCompileUnit(lc, outermostCompileUnit);
             outermostCompileUnit.addWeight(weight + WeighNodes.FUNCTION_WEIGHT);
         } else {
-            functionNode.setCompileUnit(findUnit(weight));
+            functionNode = functionNode.setCompileUnit(lc, findUnit(weight));
         }
 
-        // Recursively split nested functions
-        functionNode.accept(new NodeOperatorVisitor() {
+        final Block body = functionNode.getBody();
+        final List<FunctionNode> dc = directChildren(functionNode);
+
+        final Block newBody = (Block)body.accept(new NodeVisitor() {
+                @Override
+                public boolean enterFunctionNode(final FunctionNode nestedFunction) {
+                    return dc.contains(nestedFunction);
+                }
+
+                @Override
+                public Node leaveFunctionNode(final FunctionNode nestedFunction) {
+                    FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction);
+                    getLexicalContext().replace(nestedFunction, split);
+                    return split;
+                }
+            });
+        functionNode = functionNode.setBody(lc, newBody);
+
+        assert functionNode.getCompileUnit() != null;
+
+        return functionNode.setState(lc, CompilationState.SPLIT);
+    }
+
+    private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
+        final List<FunctionNode> dc = new ArrayList<>();
+        functionNode.accept(new NodeVisitor() {
             @Override
-            public Node enterFunctionNode(FunctionNode function) {
-                if(function == functionNode) {
-                    // Don't process outermost function (it was already processed) but descend into it to find nested
-                    // functions.
-                    return function;
+            public boolean enterFunctionNode(final FunctionNode child) {
+                if (child == functionNode) {
+                    return true;
                 }
-                // Process a nested function
-                new Splitter(compiler, function, outermostCompileUnit).split();
-                // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions.
-                return null;
+                if (getLexicalContext().getParentFunction(child) == functionNode) {
+                    dc.add(child);
+                }
+                return false;
             }
         });
-
-        functionNode.setState(CompilationState.SPLIT);
+        return dc;
     }
 
     /**
@@ -170,8 +179,8 @@
      *
      * @return new weight for the resulting block.
      */
-    private long splitBlock(final Block block, final FunctionNode function) {
-        functionNode.setIsSplit();
+    private Block splitBlock(final Block block, final FunctionNode function) {
+        getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
 
         final List<Node> splits = new ArrayList<>();
         List<Node> statements = new ArrayList<>();
@@ -186,7 +195,6 @@
                     statements = new ArrayList<>();
                     statementsWeight = 0;
                 }
-
             }
 
             if (statement.isTerminal()) {
@@ -201,9 +209,7 @@
             splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
         }
 
-        block.setStatements(splits);
-
-        return WeighNodes.weigh(block, weightCache);
+        return block.setStatements(getLexicalContext(), splits);
     }
 
     /**
@@ -218,51 +224,44 @@
         final Source source = parent.getSource();
         final long   token  = parent.getToken();
         final int    finish = parent.getFinish();
-        final String name   = function.uniqueName(SPLIT_PREFIX.tag());
-
-        final Block newBlock = new Block(source, token, finish);
-        newBlock.setFrame(new Frame(parent.getFrame()));
-        newBlock.setStatements(statements);
+        final String name   = function.uniqueName(SPLIT_PREFIX.symbolName());
 
-        final SplitNode splitNode = new SplitNode(name, functionNode, newBlock);
+        final Block newBlock = new Block(source, token, finish, statements);
 
-        splitNode.setCompileUnit(compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
-
-        return splitNode;
+        return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
     }
 
     @Override
-    public Node enterBlock(final Block block) {
+    public boolean enterBlock(final Block block) {
         if (block.isCatchBlock()) {
-            return null;
+            return false;
         }
-        lexicalContext.push(block);
 
         final long weight = WeighNodes.weigh(block, weightCache);
 
         if (weight < SPLIT_THRESHOLD) {
             weightCache.put(block, weight);
-            lexicalContext.pop(block);
-            return null;
+            return false;
         }
 
-        return block;
+        return true;
     }
 
     @Override
     public Node leaveBlock(final Block block) {
         assert !block.isCatchBlock();
 
+        Block newBlock = block;
+
         // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
         // been split already, so weigh again before splitting.
         long weight = WeighNodes.weigh(block, weightCache);
         if (weight >= SPLIT_THRESHOLD) {
-            weight = splitBlock(block, lexicalContext.getFunction(block));
+            newBlock = splitBlock(block, getLexicalContext().getFunction(block));
+            weight   = WeighNodes.weigh(newBlock, weightCache);
         }
-        weightCache.put(block, weight);
-
-        lexicalContext.pop(block);
-        return block;
+        weightCache.put(newBlock, weight);
+        return newBlock;
     }
 
     @SuppressWarnings("rawtypes")
@@ -274,7 +273,7 @@
             return literal;
         }
 
-        functionNode.setIsSplit();
+        getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT);
 
         if (literal instanceof ArrayLiteralNode) {
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
@@ -312,123 +311,12 @@
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode node) {
-        if(node == functionNode && !node.isLazy()) {
-            lexicalContext.push(node);
-            node.visitStatements(this);
-            lexicalContext.pop(node);
-        }
-        return null;
-    }
-
-    static class SplitFlowAnalyzer extends NodeVisitor {
-
-        /** Stack of visited Split nodes, deepest node first. */
-        private final Deque<SplitNode> splitStack;
-
-        /** Map of possible jump targets to containing split node */
-        private final Map<Node,SplitNode> targetNodes = new HashMap<>();
-
-        SplitFlowAnalyzer() {
-            this.splitStack = new LinkedList<>();
-        }
-
-        @Override
-        public Node enterLabelNode(final LabelNode labelNode) {
-            registerJumpTarget(labelNode.getBreakNode());
-            registerJumpTarget(labelNode.getContinueNode());
-            return labelNode;
-        }
-
-        @Override
-        public Node enterWhileNode(final WhileNode whileNode) {
-            registerJumpTarget(whileNode);
-            return whileNode;
-        }
-
-        @Override
-        public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-            registerJumpTarget(doWhileNode);
-            return doWhileNode;
-        }
-
-        @Override
-        public Node enterForNode(final ForNode forNode) {
-            registerJumpTarget(forNode);
-            return forNode;
-        }
-
-        @Override
-        public Node enterSwitchNode(final SwitchNode switchNode) {
-            registerJumpTarget(switchNode);
-            return switchNode;
-        }
-
-        @Override
-        public Node enterReturnNode(final ReturnNode returnNode) {
-            for (final SplitNode split : splitStack) {
-                split.setHasReturn(true);
-            }
-            return returnNode;
+    public boolean enterFunctionNode(final FunctionNode node) {
+        //only go into the function node for this splitter. any subfunctions are rejected
+        if (node == outermost && !node.isLazy()) {
+            return true;
         }
-
-        @Override
-        public Node enterContinueNode(final ContinueNode continueNode) {
-            searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel());
-            return continueNode;
-        }
-
-        @Override
-        public Node enterBreakNode(final BreakNode breakNode) {
-            searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel());
-            return breakNode;
-        }
-
-        @Override
-        public Node enterSplitNode(final SplitNode splitNode) {
-            splitStack.addFirst(splitNode);
-            return splitNode;
-        }
-
-        @Override
-        public Node leaveSplitNode(final SplitNode splitNode) {
-            assert splitNode == splitStack.peekFirst();
-            splitStack.removeFirst();
-            return splitNode;
-        }
-
-        /**
-         * Register the split node containing a potential jump target.
-         * @param targetNode a potential target node.
-         */
-        private void registerJumpTarget(final Node targetNode) {
-            final SplitNode splitNode = splitStack.peekFirst();
-            if (splitNode != null) {
-                targetNodes.put(targetNode, splitNode);
-            }
-        }
-
-        /**
-         * Check if a jump target is outside the current split node and its parent split nodes.
-         * @param targetNode the jump target node.
-         * @param targetLabel the jump target label.
-         */
-        private void searchJumpTarget(final Node targetNode, final Label targetLabel) {
-
-            final SplitNode targetSplit = targetNodes.get(targetNode);
-            // Note that targetSplit may be null, indicating that targetNode is in top level method.
-            // In this case we have to add the external jump target to all split nodes.
-
-            for (final SplitNode split : splitStack) {
-                if (split == targetSplit) {
-                    break;
-                }
-                final List<Label> externalTargets = split.getExternalTargets();
-                if (!externalTargets.contains(targetLabel)) {
-                    split.addExternalTarget(targetLabel);
-                }
-            }
-        }
+        return false;
     }
 }
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java	Thu May 16 11:47:51 2013 +0100
@@ -35,7 +35,6 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
@@ -101,7 +100,7 @@
      * @param weightCache cache of already calculated block weights
      */
     private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) {
-        super(null, null);
+        super();
         this.topFunction = topFunction;
         this.weightCache = weightCache;
     }
@@ -123,13 +122,13 @@
     }
 
     @Override
-    public Node enterBlock(final Block block) {
+    public boolean enterBlock(final Block block) {
         if (weightCache != null && weightCache.containsKey(block)) {
             weight += weightCache.get(block);
-            return null;
+            return false;
         }
 
-        return block;
+        return true;
     }
 
     @Override
@@ -157,12 +156,6 @@
     }
 
     @Override
-    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
-        weight += LOOP_WEIGHT;
-        return doWhileNode;
-    }
-
-    @Override
     public Node leaveExecuteNode(final ExecuteNode executeNode) {
         return executeNode;
     }
@@ -174,15 +167,15 @@
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        if(functionNode == topFunction) {
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        if (functionNode == topFunction) {
             // the function being weighted; descend into its statements
-            functionNode.visitStatements(this);
-        } else {
-            // just a reference to inner function from outer function
-            weight += FUNC_EXPR_WEIGHT;
+            return true;
+//            functionNode.visitStatements(this);
         }
-        return null;
+        // just a reference to inner function from outer function
+        weight += FUNC_EXPR_WEIGHT;
+        return false;
     }
 
     @Override
@@ -205,7 +198,7 @@
 
     @SuppressWarnings("rawtypes")
     @Override
-    public Node enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         weight += LITERAL_WEIGHT;
 
         if (literalNode instanceof ArrayLiteralNode) {
@@ -224,10 +217,10 @@
                 }
             }
 
-            return null;
+            return false;
         }
 
-        return literalNode;
+        return true;
     }
 
     @Override
@@ -249,9 +242,9 @@
     }
 
     @Override
-    public Node enterSplitNode(final SplitNode splitNode) {
+    public boolean enterSplitNode(final SplitNode splitNode) {
         weight += SPLIT_WEIGHT;
-        return null;
+        return false;
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/BooleanType.java	Thu May 16 11:47:51 2013 +0100
@@ -93,12 +93,6 @@
     }
 
     @Override
-    public Type loadEmpty(final MethodVisitor method) {
-        assert false : "unsupported operation";
-        return null;
-    }
-
-    @Override
     public void _return(final MethodVisitor method) {
         method.visitInsn(IRETURN);
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/IntType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/IntType.java	Thu May 16 11:47:51 2013 +0100
@@ -241,12 +241,6 @@
     }
 
     @Override
-    public Type loadEmpty(final MethodVisitor method) {
-        assert false : "unsupported operation";
-        return null;
-    }
-
-    @Override
     public Type cmp(final MethodVisitor method, final boolean isCmpG) {
         assert false : "unsupported operation";
         return null;
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/LongType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/LongType.java	Thu May 16 11:47:51 2013 +0100
@@ -217,12 +217,6 @@
     }
 
     @Override
-    public Type loadEmpty(final MethodVisitor method) {
-        assert false : "unsupported operation";
-        return null;
-    }
-
-    @Override
     public Type cmp(final MethodVisitor method, final boolean isCmpG) {
         return cmp(method);
     }
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/NumberType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/NumberType.java	Thu May 16 11:47:51 2013 +0100
@@ -89,12 +89,6 @@
     }
 
     @Override
-    public Type loadEmpty(final MethodVisitor method) {
-        assert false : "unsupported operation";
-        return null;
-    }
-
-    @Override
     public Type ldc(final MethodVisitor method, final Object c) {
         assert c instanceof Double;
 
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java	Thu May 16 11:47:51 2013 +0100
@@ -616,6 +616,12 @@
         return this;
     }
 
+    @Override
+    public Type loadEmpty(final MethodVisitor method) {
+        assert false : "unsupported operation";
+        return null;
+    }
+
     /**
      * Superclass logic for pop for all types
      *
@@ -663,7 +669,6 @@
                 method.visitInsn(SWAP);
             }
         }
-
     }
 
     /**
@@ -841,12 +846,6 @@
         }
 
         @Override
-        public Type loadEmpty(final MethodVisitor method) {
-            assert false : "unsupported operation";
-            return null;
-        }
-
-        @Override
         public Type convert(final MethodVisitor method, final Type to) {
             assert false : "unsupported operation";
             return null;
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,23 +25,18 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a property access (period operator.)
- *
  */
-public class AccessNode extends BaseNode implements TypeOverride<AccessNode> {
+@Immutable
+public final class AccessNode extends BaseNode {
     /** Property ident. */
-    private IdentNode property;
-
-    /** Does this node have a type override */
-    private boolean hasCallSiteType;
+    private final IdentNode property;
 
     /**
      * Constructor
@@ -53,49 +48,13 @@
      * @param property  property
      */
     public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) {
-        super(source, token, finish, base);
-
-        this.start    = base.getStart();
+        super(source, token, finish, base, false, false);
         this.property = property.setIsPropertyName();
     }
 
-    /**
-     * Copy constructor
-     *
-     * @param accessNode  source node
-     */
-    public AccessNode(final AccessNode accessNode) {
-        this(accessNode, new CopyState());
-    }
-
-    /**
-     * Internal copy constructor
-     *
-     * @param accessNode  source node
-     * @param cs          copy state
-     */
-    protected AccessNode(final AccessNode accessNode, final CopyState cs) {
-        super(accessNode, cs);
-        this.property = (IdentNode)cs.existingOrCopy(accessNode.getProperty());
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new AccessNode(this, cs);
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        final AccessNode accessNode = (AccessNode)other;
-        return property.equals(accessNode.getProperty());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ property.hashCode();
+    private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
+        super(accessNode, base, isFunction, hasCallSiteType);
+        this.property = property;
     }
 
     /**
@@ -104,12 +63,11 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterAccessNode(this) != null) {
-            base = base.accept(visitor);
-            property = (IdentNode)property.accept(visitor);
-            return visitor.leaveAccessNode(this);
+        if (visitor.enterAccessNode(this)) {
+            return visitor.leaveAccessNode(
+                setBase(base.accept(visitor)).
+                setProperty((IdentNode)property.accept(visitor)));
         }
-
         return this;
     }
 
@@ -117,7 +75,7 @@
     public void toString(final StringBuilder sb) {
         final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true);
 
-        if (hasCallSiteType) {
+        if (hasCallSiteType()) {
             sb.append('{');
             final String desc = getType().getDescriptor();
             sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
@@ -147,19 +105,34 @@
         return property;
     }
 
-    @Override
-    public AccessNode setType(final Type type) {
-        if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
-            ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
+    private AccessNode setBase(final Node base) {
+        if (this.base == base) {
+            return this;
         }
-        property = property.setType(type);
-        getSymbol().setTypeOverride(type); //always a temp so this is fine.
-        hasCallSiteType = true;
-        return this;
+        return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
+    }
+
+
+    private AccessNode setProperty(final IdentNode property) {
+        if (this.property == property) {
+            return this;
+        }
+        return new AccessNode(this, base, property, isFunction(), hasCallSiteType());
     }
 
     @Override
-    public boolean canHaveCallSiteType() {
-        return true; //carried by the symbol and always the same nodetype==symboltype
+    public AccessNode setType(final Type type) {
+        logTypeChange(type);
+        getSymbol().setTypeOverride(type); //always a temp so this is fine.
+        return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType());
     }
+
+    @Override
+    public BaseNode setIsFunction() {
+        if (isFunction()) {
+            return this;
+        }
+        return new AccessNode(this, base, property, true, hasCallSiteType());
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,6 +25,10 @@
 
 package jdk.nashorn.internal.ir;
 
+import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
+import jdk.nashorn.internal.codegen.ObjectClassGenerator;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
@@ -33,12 +37,15 @@
  * @see AccessNode
  * @see IndexNode
  */
-public abstract class BaseNode extends Node implements FunctionCall {
+@Immutable
+public abstract class BaseNode extends Node implements FunctionCall, TypeOverride<BaseNode> {
 
     /** Base Node. */
-    protected Node base;
+    protected final Node base;
 
-    private boolean function;
+    private final boolean isFunction;
+
+    private final boolean hasCallSiteType;
 
     /**
      * Constructor
@@ -47,37 +54,28 @@
      * @param token  token
      * @param finish finish
      * @param base   base node
+     * @param isFunction is this a function
+     * @param hasCallSiteType does this access have a callsite type
      */
-    public BaseNode(final Source source, final long token, final int finish, final Node base) {
-        super(source, token, finish);
-        this.base = base;
-        setStart(base.getStart());
+    public BaseNode(final Source source, final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+        super(source, token, base.getStart(), finish);
+        this.base            = base;
+        this.isFunction      = isFunction;
+        this.hasCallSiteType = hasCallSiteType;
     }
 
     /**
-     * Copy constructor
-     *
-     * @param baseNode the base node
-     * @param cs       a copy state
+     * Copy constructor for immutable nodes
+     * @param baseNode node to inherit from
+     * @param base base
+     * @param isFunction is this a function
+     * @param hasCallSiteType does this access have a callsite type
      */
-    protected BaseNode(final BaseNode baseNode, final CopyState cs) {
+    protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
         super(baseNode);
-        this.base = cs.existingOrCopy(baseNode.getBase());
-        setStart(base.getStart());
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        final BaseNode baseNode = (BaseNode)other;
-        return base.equals(baseNode.getBase());
-    }
-
-    @Override
-    public int hashCode() {
-        return base.hashCode();
+        this.base            = base;
+        this.isFunction      = isFunction;
+        this.hasCallSiteType = hasCallSiteType;
     }
 
     /**
@@ -88,25 +86,37 @@
         return base;
     }
 
-    /**
-     * Reset the base node for this access
-     * @param base new base node
-     */
-    public void setBase(final Node base) {
-        this.base = base;
-    }
-
     @Override
     public boolean isFunction() {
-        return function;
+        return isFunction;
     }
 
     /**
      * Mark this node as being the callee operand of a {@link CallNode}.
      * @return a base node identical to this one in all aspects except with its function flag set.
      */
-    public BaseNode setIsFunction() {
-        function = true;
-        return this;
+    public abstract BaseNode setIsFunction();
+
+    @Override
+    public boolean canHaveCallSiteType() {
+        return true; //carried by the symbol and always the same nodetype==symboltype
+    }
+
+    /**
+     * Does the access have a call site type override?
+     * @return true if overridden
+     */
+    protected boolean hasCallSiteType() {
+        return hasCallSiteType;
+    }
+
+    /**
+     * Debug type change
+     * @param type new type
+     */
+    protected final void logTypeChange(final Type type) {
+        if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
+            ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
+        }
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java	Thu May 16 11:47:51 2013 +0100
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.ir;
 
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Source;
@@ -33,9 +34,12 @@
 /**
  * BinaryNode nodes represent two operand operations.
  */
-public class BinaryNode extends UnaryNode {
+@Immutable
+public final class BinaryNode extends Node implements Assignment<Node> {
     /** Left hand side argument. */
-    private Node lhs;
+    private final Node lhs;
+
+    private final Node rhs;
 
     /**
      * Constructor
@@ -46,28 +50,15 @@
      * @param rhs    right hand side
      */
     public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) {
-        super(source, token, rhs);
-
-        start  = lhs.getStart();
-        finish = rhs.getFinish();
-
-        this.lhs = lhs;
+        super(source, token, lhs.getStart(), rhs.getFinish());
+        this.lhs   = lhs;
+        this.rhs   = rhs;
     }
 
-    /**
-     * Copy constructor
-     *
-     * @param binaryNode the binary node
-     * @param cs         copy state
-     */
-    protected BinaryNode(final BinaryNode binaryNode, final CopyState cs) {
-        super(binaryNode, cs);
-        lhs = cs.existingOrCopy(binaryNode.lhs);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new BinaryNode(this, cs);
+    private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) {
+        super(binaryNode);
+        this.lhs = lhs;
+        this.rhs = rhs;
     }
 
     /**
@@ -149,28 +140,14 @@
         return rhs();
     }
 
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        return lhs.equals(((BinaryNode)other).lhs());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ lhs().hashCode();
-    }
-
     /**
      * Assist in IR navigation.
      * @param visitor IR navigating visitor.
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterBinaryNode(this) != null) {
-            // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers
-            return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor)));
+        if (visitor.enterBinaryNode(this)) {
+            return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor)));
         }
 
         return this;
@@ -231,14 +208,35 @@
     }
 
     /**
+     * Get the right hand side expression for this node
+     * @return the left hand side expression
+     */
+    public Node rhs() {
+        return rhs;
+    }
+
+    /**
      * Set the left hand side expression for this node
      * @param lhs new left hand side expression
      * @return a node equivalent to this one except for the requested change.
      */
     public BinaryNode setLHS(final Node lhs) {
-        if(this.lhs == lhs) return this;
-        final BinaryNode n = (BinaryNode)clone();
-        n.lhs = lhs;
-        return n;
+        if (this.lhs == lhs) {
+            return this;
+        }
+        return new BinaryNode(this, lhs, rhs);
     }
+
+    /**
+     * Set the right hand side expression for this node
+     * @param rhs new left hand side expression
+     * @return a node equivalent to this one except for the requested change.
+     */
+    public BinaryNode setRHS(final Node rhs) {
+        if (this.rhs == rhs) {
+            return this;
+        }
+        return new BinaryNode(this, lhs, rhs);
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/Block.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java	Thu May 16 11:47:51 2013 +0100
@@ -27,14 +27,15 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.ListIterator;
-import jdk.nashorn.internal.codegen.Frame;
+import java.util.Map;
 import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
@@ -42,97 +43,79 @@
  * IR representation for a list of statements and functions. All provides the
  * basis for script body.
  */
-public class Block extends Node {
+@Immutable
+public class Block extends BreakableNode implements Flags<Block> {
     /** List of statements */
-    protected List<Node> statements;
+    protected final List<Node> statements;
 
-    /** Symbol table. */
-    protected final HashMap<String, Symbol> symbols;
-
-    /** Variable frame. */
-    protected Frame frame;
+    /** Symbol table - keys must be returned in the order they were put in. */
+    protected final Map<String, Symbol> symbols;
 
     /** Entry label. */
     protected final Label entryLabel;
 
-    /** Break label. */
-    protected final Label breakLabel;
+    /** Does the block/function need a new scope? */
+    protected final int flags;
+
+    /** Flag indicating that this block needs scope */
+    public static final int NEEDS_SCOPE = 1 << 0;
 
-    /** Does the block/function need a new scope? */
-    protected boolean needsScope;
+    /**
+     * Flag indicating whether this block needs
+     * self symbol assignment at the start. This is used only for
+     * blocks that are the bodies of function nodes who refer to themselves
+     * by name. It causes codegen to insert a var [fn_name] = __callee__
+     * at the start of the body
+     */
+    public static final int NEEDS_SELF_SYMBOL = 1 << 1;
+
+    /**
+     * Is this block tagged as terminal based on its contents
+     * (usually the last statement)
+     */
+    public static final int IS_TERMINAL = 1 << 2;
 
     /**
      * Constructor
      *
-     * @param source   source code
-     * @param token    token
-     * @param finish   finish
+     * @param source     source code
+     * @param token      token
+     * @param finish     finish
+     * @param statements statements
      */
-    public Block(final Source source, final long token, final int finish) {
-        super(source, token, finish);
+    public Block(final Source source, final long token, final int finish, final Node... statements) {
+        super(source, token, finish, new Label("block_break"));
 
-        this.statements = new ArrayList<>();
-        this.symbols    = new HashMap<>();
+        this.statements = Arrays.asList(statements);
+        this.symbols    = new LinkedHashMap<>();
         this.entryLabel = new Label("block_entry");
-        this.breakLabel = new Label("block_break");
+        this.flags     =  0;
     }
 
     /**
-     * Internal copy constructor
+     * Constructor
      *
-     * @param block the source block
-     * @param cs    the copy state
+     * @param source     source code
+     * @param token      token
+     * @param finish     finish
+     * @param statements statements
      */
-    protected Block(final Block block, final CopyState cs) {
-        super(block);
+    public Block(final Source source, final long token, final int finish, final List<Node> statements) {
+        this(source, token, finish, statements.toArray(new Node[statements.size()]));
+    }
 
-        this.statements = new ArrayList<>();
-        for (final Node statement : block.getStatements()) {
-            statements.add(cs.existingOrCopy(statement));
-        }
-        this.symbols    = new HashMap<>();
-        this.frame      = block.frame == null ? null : block.frame.copy();
+    private Block(final Block block, final int finish, final List<Node> statements, final int flags) {
+        super(block);
+        this.statements = statements;
+        this.flags      = flags;
+        this.symbols    = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
         this.entryLabel = new Label(block.entryLabel);
-        this.breakLabel = new Label(block.breakLabel);
-
-        assert block.symbols.isEmpty() : "must not clone with symbols";
+        this.finish = finish;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new Block(this, cs);
-    }
-
-    /**
-     * Add a new statement to the statement list.
-     *
-     * @param statement Statement node to add.
-     */
-    public void addStatement(final Node statement) {
-        if (statement != null) {
-            statements.add(statement);
-            if (getFinish() < statement.getFinish()) {
-                setFinish(statement.getFinish());
-            }
-        }
-    }
-
-    /**
-     * Prepend statements to the statement list
-     *
-     * @param prepended statement to add
-     */
-    public void prependStatements(final List<Node> prepended) {
-        statements.addAll(0, prepended);
-    }
-
-    /**
-     * Add a list of statements to the statement list.
-     *
-     * @param statementList Statement nodes to add.
-     */
-    public void addStatements(final List<Node> statementList) {
-        statements.addAll(statementList);
+    public Node ensureUniqueLabels(final LexicalContext lc) {
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
     }
 
     /**
@@ -142,19 +125,9 @@
      * @return new or same node
      */
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        final Block saveBlock = visitor.getCurrentBlock();
-        visitor.setCurrentBlock(this);
-
-        try {
-            // Ignore parent to avoid recursion.
-
-            if (visitor.enterBlock(this) != null) {
-                visitStatements(visitor);
-                return visitor.leaveBlock(this);
-            }
-        } finally {
-            visitor.setCurrentBlock(saveBlock);
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterBlock(this)) {
+            return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements)));
         }
 
         return this;
@@ -222,11 +195,18 @@
     }
 
     /**
-     * Get the break label for this block
-     * @return the break label
+     * Tag block as terminal or non terminal
+     * @param lc          lexical context
+     * @param isTerminal is block terminal
+     * @return same block, or new if flag changed
      */
-    public Label getBreakLabel() {
-        return breakLabel;
+    public Block setIsTerminal(final LexicalContext lc, final boolean isTerminal) {
+        return isTerminal ? setFlag(lc, IS_TERMINAL) : clearFlag(lc, IS_TERMINAL);
+    }
+
+    @Override
+    public boolean isTerminal() {
+        return getFlag(IS_TERMINAL);
     }
 
     /**
@@ -238,23 +218,6 @@
     }
 
     /**
-     * Get the frame for this block
-     * @return the frame
-     */
-    public Frame getFrame() {
-        return frame;
-    }
-
-    /**
-     * Reset the frame for this block
-     *
-     * @param frame  the new frame
-     */
-    public void setFrame(final Frame frame) {
-        this.frame = frame;
-    }
-
-    /**
      * Get the list of statements in this block
      *
      * @return a list of statements
@@ -264,21 +227,21 @@
     }
 
     /**
-     * Applies the specified visitor to all statements in the block.
-     * @param visitor the visitor.
-     */
-    public void visitStatements(NodeVisitor visitor) {
-        for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) {
-            stmts.set(stmts.next().accept(visitor));
-        }
-    }
-    /**
      * Reset the statement list for this block
      *
-     * @param statements  new statement list
+     * @param lc lexical context
+     * @param statements new statement list
+     * @return new block if statements changed, identity of statements == block.statements
      */
-    public void setStatements(final List<Node> statements) {
-        this.statements = statements;
+    public Block setStatements(final LexicalContext lc, final List<Node> statements) {
+        if (this.statements == statements) {
+            return this;
+        }
+        int lastFinish = 0;
+        if (!statements.isEmpty()) {
+            lastFinish = statements.get(statements.size() - 1).getFinish();
+        }
+        return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags));
     }
 
     /**
@@ -297,39 +260,65 @@
      * @return true if this function needs a scope
      */
     public boolean needsScope() {
-        return needsScope;
+        return (flags & NEEDS_SCOPE) == NEEDS_SCOPE;
+    }
+
+    @Override
+    public Block setFlags(final LexicalContext lc, int flags) {
+        if (this.flags == flags) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags));
+    }
+
+    @Override
+    public Block clearFlag(final LexicalContext lc, int flag) {
+        return setFlags(lc, flags & ~flag);
+    }
+
+    @Override
+    public Block setFlag(final LexicalContext lc, int flag) {
+        return setFlags(lc, flags | flag);
+    }
+
+    @Override
+    public boolean getFlag(final int flag) {
+        return (flags & flag) == flag;
     }
 
     /**
      * Set the needs scope flag.
+     * @param lc lexicalContext
+     * @return new block if state changed, otherwise this
      */
-    public void setNeedsScope() {
-        needsScope = true;
+    public Block setNeedsScope(final LexicalContext lc) {
+        if (needsScope()) {
+            return this;
+        }
+
+        return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE));
     }
 
     /**
-     * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not
-     * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol
-     * will be marked as one that needs to have its own scope.
-     * @param symbol the symbol being used.
-     * @param ancestors the iterator over block's containing lexical context
+     * Computationally determine the next slot for this block,
+     * indexed from 0. Use this as a relative base when computing
+     * frames
+     * @return next slot
      */
-    public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
-        if(symbol.getBlock() == this) {
-            setNeedsScope();
-        } else {
-            setUsesParentScopeSymbol(symbol, ancestors);
+    public int nextSlot() {
+        final Iterator<Symbol> iter = symbolIterator();
+        int next = 0;
+        while (iter.hasNext()) {
+        final Symbol symbol = iter.next();
+        if (symbol.hasSlot()) {
+            next += symbol.slotCount();
         }
+        }
+        return next;
     }
 
-    /**
-     * Invoked when this block uses a scope symbol defined in one of its ancestors.
-     * @param symbol the scope symbol being used
-     * @param ancestors iterator over ancestor blocks
-     */
-    void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
-        if(ancestors.hasNext()) {
-            ancestors.next().setUsesScopeSymbol(symbol, ancestors);
-        }
+    @Override
+    protected boolean isBreakableWithoutLabel() {
+        return false;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,120 @@
+/*
+ * 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.ir;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * This is a subclass of lexical context used for filling
+ * blocks (and function nodes) with statements. When popping
+ * a block from the lexical context, any statements that have
+ * been generated in it are commited to the block. This saves
+ * unnecessary object mutations and lexical context replacement
+ */
+public class BlockLexicalContext extends LexicalContext {
+    /** statement stack, each block on the lexical context maintains one of these, which is
+     *  committed to the block on pop */
+    private Deque<List<Node>> sstack = new ArrayDeque<>();
+
+    /** Last non debug statement emitted in this context */
+    protected Node lastStatement;
+
+    @Override
+    public <T extends LexicalContextNode> T push(final T node) {
+        T pushed = super.push(node);
+        if (node instanceof Block) {
+            sstack.push(new ArrayList<Node>());
+        }
+        return pushed;
+    }
+
+    /**
+     * Get the statement list from the stack, possibly filtered
+     * @return statement list
+     */
+    protected List<Node> popStatements() {
+        return sstack.pop();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends LexicalContextNode> T pop(final T node) {
+        T expected = node;
+        if (node instanceof Block) {
+            final List<Node> newStatements = popStatements();
+            expected = (T)((Block)node).setStatements(this, newStatements);
+            if (!sstack.isEmpty()) {
+                lastStatement = lastStatement(sstack.peek());
+            }
+        }
+        return super.pop(expected);
+    }
+
+    /**
+     * Append a statement to the block being generated
+     * @param statement statement to add
+     */
+    public void appendStatement(final Node statement) {
+        assert statement != null;
+        sstack.peek().add(statement);
+        if (!statement.isDebug()) {
+            lastStatement = statement;
+        }
+    }
+
+    /**
+     * Prepend a statement to the block being generated
+     * @param statement statement to prepend
+     * @return the prepended statement
+     */
+    public Node prependStatement(final Node statement) {
+        assert statement != null;
+        sstack.peek().add(0, statement);
+        return statement;
+    }
+
+    /**
+     * Get the last (non debug) statement that was emitted into a block
+     * @return the last statement emitted
+     */
+    public Node getLastStatement() {
+        return lastStatement;
+    }
+
+    private static Node lastStatement(final List<Node> statements) {
+        for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) {
+            final Node node = iter.previous();
+            if (!node.isDebug()) {
+                return node;
+            }
+        }
+        return null;
+    }
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,37 +25,34 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for {@code break} statements.
  */
-public class BreakNode extends LabeledNode {
+@Immutable
+public final class BreakNode extends Node {
 
-     /**
+    private final IdentNode label;
+
+    /**
      * Constructor
      *
-     * @param source     source code
-     * @param token      token
-     * @param finish     finish
-     * @param labelNode  break label
-     * @param targetNode node to break to
-     * @param tryChain   surrounding try chain
+     * @param source source code
+     * @param token  token
+     * @param finish finish
+     * @param label  label for break or null if none
      */
-    public BreakNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) {
-        super(source, token, finish, labelNode, targetNode, tryChain);
-        setHasGoto();
-    }
-
-    private BreakNode(final BreakNode breakNode, final CopyState cs) {
-        super(breakNode, cs);
+    public BreakNode(final Source source, final long token, final int finish, final IdentNode label) {
+        super(source, token, finish);
+        this.label = label;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new BreakNode(this, cs);
+    public boolean hasGoto() {
+        return true;
     }
 
     /**
@@ -64,7 +61,7 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterBreakNode(this) != null) {
+        if (visitor.enterBreakNode(this)) {
             return visitor.leaveBreakNode(this);
         }
 
@@ -72,26 +69,20 @@
     }
 
     /**
-     * Return the target label of this break node.
-     * @return the target label.
+     * Get the label for this break node
+     * @return label, or null if none
      */
-    public Label getTargetLabel() {
-        if (targetNode instanceof BreakableNode) {
-            return ((BreakableNode)targetNode).getBreakLabel();
-        } else if (targetNode instanceof Block) {
-            return ((Block)targetNode).getBreakLabel();
-        }
-
-        throw new AssertionError("Invalid break target " + targetNode.getClass());
+    public IdentNode getLabel() {
+        return label;
     }
 
     @Override
     public void toString(final StringBuilder sb) {
         sb.append("break");
 
-        if (labelNode != null) {
+        if (label != null) {
             sb.append(' ');
-            labelNode.getLabel().toString(sb);
+            label.toString(sb);
         }
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/BreakableNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,27 +25,34 @@
 
 package jdk.nashorn.internal.ir;
 
+import java.util.Arrays;
+import java.util.List;
+
 import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * This class represents a node from which control flow can execute
  * a {@code break} statement
  */
-public abstract class BreakableNode extends Node {
+@Immutable
+public abstract class BreakableNode extends LexicalContextNode {
 
     /** break label. */
-    protected Label breakLabel;
+    protected final Label breakLabel;
 
     /**
      * Constructor
      *
-     * @param source   source code
-     * @param token    token
-     * @param finish   finish
+     * @param source     source code
+     * @param token      token
+     * @param finish     finish
+     * @param breakLabel break label
      */
-    public BreakableNode(final Source source, final long token, final int finish) {
+    protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) {
         super(source, token, finish);
+        this.breakLabel = breakLabel;
     }
 
     /**
@@ -55,6 +62,19 @@
      */
     protected BreakableNode(final BreakableNode breakableNode) {
         super(breakableNode);
+        this.breakLabel = new Label(breakableNode.getBreakLabel());
+    }
+
+    @Override
+    public abstract Node ensureUniqueLabels(final LexicalContext lc);
+
+    /**
+     * Check whether this can be broken out from without using a label,
+     * e.g. everything but Blocks, basically
+     * @return true if breakable without label
+     */
+    protected boolean isBreakableWithoutLabel() {
+        return true;
     }
 
     /**
@@ -65,4 +85,14 @@
         return breakLabel;
     }
 
+    /**
+     * Return the labels associated with this node. Breakable nodes that
+     * aren't LoopNodes only have a break label -> the location immediately
+     * afterwards the node in code
+     * @return list of labels representing locations around this node
+     */
+    public List<Label> getLabels() {
+        return Arrays.asList(breakLabel);
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,49 +25,48 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a function call.
- *
  */
-public class CallNode extends Node implements TypeOverride<CallNode> {
+@Immutable
+public final class CallNode extends LexicalContextNode implements TypeOverride<CallNode> {
 
-    private Type type;
+    private final Type type;
 
     /** Function identifier or function body. */
-    private Node function;
+    private final Node function;
 
     /** Call arguments. */
-    private List<Node> args;
+    private final List<Node> args;
 
-    /** flag - is new expression */
-    private boolean isNew;
+    /** Is this a "new" operation */
+    public static final int IS_NEW        = 0x1;
 
-    /** flag - is in with block */
-    private boolean inWithBlock;
+    private final int flags;
 
     /**
      * Arguments to be passed to builtin {@code eval} function
      */
     public static class EvalArgs {
         /** evaluated code */
-        private Node code;
+        private final Node code;
 
         /** 'this' passed to evaluated code */
-        private IdentNode evalThis;
+        private final IdentNode evalThis;
 
         /** location string for the eval call */
-        final private String location;
+        private final String location;
 
         /** is this call from a strict context? */
-        final private boolean strictMode;
+        private final boolean strictMode;
 
         /**
          * Constructor
@@ -92,12 +91,11 @@
             return code;
         }
 
-        /**
-         * Set the code that is to be eval.ed by this eval function
-         * @param code the code as an AST node
-         */
-        public void setCode(final Node code) {
-            this.code = code;
+        private EvalArgs setCode(final Node code) {
+            if (this.code == code) {
+                return this;
+            }
+            return new EvalArgs(code, evalThis, location, strictMode);
         }
 
         /**
@@ -108,12 +106,11 @@
             return this.evalThis;
         }
 
-        /**
-         * Set the {@code this} symbol used to invoke this eval call
-         * @param evalThis the {@code this} symbol
-         */
-        public void setThis(final IdentNode evalThis) {
-            this.evalThis = evalThis;
+        private EvalArgs setThis(final IdentNode evalThis) {
+            if (this.evalThis == evalThis) {
+                return this;
+            }
+            return new EvalArgs(code, evalThis, location, strictMode);
         }
 
         /**
@@ -135,7 +132,7 @@
 
     /** arguments for 'eval' call. Non-null only if this call node is 'eval' */
     @Ignore
-    private EvalArgs evalArgs;
+    private final EvalArgs evalArgs;
 
     /**
      * Constructors
@@ -149,28 +146,22 @@
     public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) {
         super(source, token, finish);
 
-        setStart(function.getStart());
-
-        this.function     = function;
-        this.args         = args;
+        this.function = function;
+        this.args     = args;
+        this.flags    = 0;
+        this.type     = null;
+        this.evalArgs = null;
     }
 
-    private CallNode(final CallNode callNode, final CopyState cs) {
+    private CallNode(final CallNode callNode, final Node function, final List<Node> args, final int flags, final Type type, final EvalArgs evalArgs) {
         super(callNode);
-
-        final List<Node> newArgs = new ArrayList<>();
-
-        for (final Node arg : callNode.args) {
-            newArgs.add(cs.existingOrCopy(arg));
-        }
-
-        this.function     = cs.existingOrCopy(callNode.function);     //TODO existing or same?
-        this.args         = newArgs;
-        this.isNew        = callNode.isNew;
-        this.inWithBlock  = callNode.inWithBlock;
+        this.function = function;
+        this.args = args;
+        this.flags = flags;
+        this.type = type;
+        this.evalArgs = evalArgs;
     }
 
-
     @Override
     public Type getType() {
         if (hasCallSiteType()) {
@@ -181,8 +172,10 @@
 
     @Override
     public CallNode setType(final Type type) {
-        this.type = type;
-        return this;
+        if (this.type == type) {
+            return this;
+        }
+        return new CallNode(this, function, args, flags, type, evalArgs);
     }
 
     private boolean hasCallSiteType() {
@@ -194,11 +187,6 @@
         return true;
     }
 
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new CallNode(this, cs);
-    }
-
     /**
      * Assist in IR navigation.
      *
@@ -207,15 +195,22 @@
      * @return node or replacement
      */
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterCallNode(this) != null) {
-            function = function.accept(visitor);
-
-            for (int i = 0, count = args.size(); i < count; i++) {
-                args.set(i, args.get(i).accept(visitor));
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterCallNode(this)) {
+            final CallNode newCallNode = (CallNode)visitor.leaveCallNode(
+                    setFunction(function.accept(visitor)).
+                    setArgs(Node.accept(visitor, Node.class, args)).
+                    setFlags(flags).
+                    setType(type).
+                    setEvalArgs(evalArgs == null ?
+                            null :
+                            evalArgs.setCode(evalArgs.getCode().accept(visitor)).
+                                setThis((IdentNode)evalArgs.getThis().accept(visitor))));
+            // Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice,
+            // setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now.
+            if(this != newCallNode) {
+                return Node.replaceInLexicalContext(lc, this, newCallNode);
             }
-
-            return visitor.leaveCallNode(this);
         }
 
         return this;
@@ -226,7 +221,7 @@
         if (hasCallSiteType()) {
             sb.append('{');
             final String desc = getType().getDescriptor();
-            sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
+            sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor());
             sb.append('}');
         }
 
@@ -261,8 +256,11 @@
      * Reset the arguments for the call
      * @param args new arguments list
      */
-    public void setArgs(final List<Node> args) {
-        this.args = args;
+    private CallNode setArgs(final List<Node> args) {
+        if (this.args == args) {
+            return this;
+        }
+        return new CallNode(this, function, args, flags, type, evalArgs);
     }
 
     /**
@@ -278,9 +276,13 @@
      * {@code eval}
      *
      * @param evalArgs eval args
+     * @return same node or new one on state change
      */
-    public void setEvalArgs(final EvalArgs evalArgs) {
-        this.evalArgs = evalArgs;
+    public CallNode setEvalArgs(final EvalArgs evalArgs) {
+        if (this.evalArgs == evalArgs) {
+            return this;
+        }
+        return new CallNode(this, function, args, flags, type, evalArgs);
     }
 
     /**
@@ -301,10 +303,14 @@
 
     /**
      * Reset the function expression that this call invokes
-     * @param node the function
+     * @param function the function
+     * @return same node or new one on state change
      */
-    public void setFunction(final Node node) {
-        function = node;
+    public CallNode setFunction(final Node function) {
+        if (this.function == function) {
+            return this;
+        }
+        return new CallNode(this, function, args, flags, type, evalArgs);
     }
 
     /**
@@ -312,28 +318,21 @@
      * @return true if this a new operation
      */
     public boolean isNew() {
-        return isNew;
+        return (flags & IS_NEW) == IS_NEW;
     }
 
     /**
      * Flag this call as a new operation
+     * @return same node or new one on state change
      */
-    public void setIsNew() {
-        this.isNew = true;
+    public CallNode setIsNew() {
+        return setFlags(IS_NEW);
     }
 
-    /**
-     * Check if this call is inside a {@code with} block
-     * @return true if the call is inside a {@code with} block
-     */
-    public boolean inWithBlock() {
-        return inWithBlock;
-    }
-
-    /**
-     * Flag this call to be inside a {@code with} block
-     */
-    public void setInWithBlock() {
-        this.inWithBlock = true;
+    private CallNode setFlags(final int flags) {
+        if (this.flags == flags) {
+            return this;
+        }
+        return new CallNode(this, function, args, flags, type, evalArgs);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java	Thu May 16 11:47:51 2013 +0100
@@ -26,19 +26,21 @@
 package jdk.nashorn.internal.ir;
 
 import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of CASE clause.
- *
+ * Case nodes are not BreakableNodes, but the SwitchNode is
  */
-public class CaseNode extends BreakableNode {
+@Immutable
+public final class CaseNode extends Node {
     /** Test expression. */
-    private Node test;
+    private final Node test;
 
     /** Statements. */
-    private Block body;
+    private final Block body;
 
     /** Case entry label. */
     private final Label entry;
@@ -60,17 +62,17 @@
         this.entry = new Label("entry");
     }
 
-    private CaseNode(final CaseNode caseNode, final CopyState cs) {
+    CaseNode(final CaseNode caseNode, final Node test, final Block body) {
         super(caseNode);
 
-        this.test  = cs.existingOrCopy(caseNode.test);
-        this.body  = (Block)cs.existingOrCopy(caseNode.body);
+        this.test  = test;
+        this.body  = body;
         this.entry = new Label(caseNode.entry);
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new CaseNode(this, cs);
+    public boolean isTerminal() {
+        return body.isTerminal();
     }
 
     /**
@@ -79,15 +81,11 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterCaseNode(this) != null) {
-            if (test != null) {
-                test = test.accept(visitor);
-            }
-            if (body != null) {
-                body = (Block)body.accept(visitor);
-            }
+        if (visitor.enterCaseNode(this)) {
+            final Node  newTest = test == null ? null : test.accept(visitor);
+            final Block newBody = body == null ? null : (Block)body.accept(visitor);
 
-            return visitor.leaveCaseNode(this);
+            return visitor.leaveCaseNode(setTest(newTest).setBody(newBody));
         }
 
         return this;
@@ -131,8 +129,19 @@
     /**
      * Reset the test expression for this case node
      * @param test new test expression
+     * @return new or same CaseNode
      */
-    public void setTest(final Node test) {
-        this.test = test;
+    public CaseNode setTest(final Node test) {
+        if (this.test == test) {
+            return this;
+        }
+        return new CaseNode(this, test, body);
+    }
+
+    private CaseNode setBody(final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return new CaseNode(this, test, body);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,26 +25,23 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a catch clause.
- *
  */
-public class CatchNode extends Node {
+@Immutable
+public final class CatchNode extends Node {
     /** Exception identifier. */
-    private IdentNode exception;
+    private final IdentNode exception;
 
     /** Exception condition. */
-    private Node exceptionCondition;
+    private final Node exceptionCondition;
 
     /** Catch body. */
-    private Block body;
-
-    /** Is rethrow - e.g. synthetic catch block for e.g. finallies, the parser case where
-     * there has to be at least on catch for syntactic validity */
-    private boolean isSyntheticRethrow;
+    private final Block body;
 
     /**
      * Constructors
@@ -64,18 +61,12 @@
         this.body               = body;
     }
 
-    private CatchNode(final CatchNode catchNode, final CopyState cs) {
+    private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) {
         super(catchNode);
 
-        this.exception          = (IdentNode)cs.existingOrCopy(catchNode.exception);
-        this.exceptionCondition = cs.existingOrCopy(catchNode.exceptionCondition);
-        this.body               = (Block)cs.existingOrCopy(catchNode.body);
-        this.isSyntheticRethrow = catchNode.isSyntheticRethrow;
-     }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new CatchNode(this, cs);
+        this.exception          = exception;
+        this.exceptionCondition = exceptionCondition;
+        this.body               = body;
     }
 
     /**
@@ -84,21 +75,22 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterCatchNode(this) != null) {
-            exception = (IdentNode)exception.accept(visitor);
-
-            if (exceptionCondition != null) {
-                exceptionCondition = exceptionCondition.accept(visitor);
-            }
-
-            body = (Block)body.accept(visitor);
-            return visitor.leaveCatchNode(this);
+        if (visitor.enterCatchNode(this)) {
+            return visitor.leaveCatchNode(
+                setException((IdentNode)exception.accept(visitor)).
+                setExceptionCondition(exceptionCondition == null ? null : exceptionCondition.accept(visitor)).
+                setBody((Block)body.accept(visitor)));
         }
 
         return this;
     }
 
     @Override
+    public boolean isTerminal() {
+        return body.isTerminal();
+    }
+
+    @Override
     public void toString(final StringBuilder sb) {
         sb.append(" catch (");
         exception.toString(sb);
@@ -111,23 +103,6 @@
     }
 
     /**
-     * Check if this catch is a synthetic rethrow
-     * @return true if this is a synthetic rethrow
-     */
-    public boolean isSyntheticRethrow() {
-        return isSyntheticRethrow;
-    }
-
-    /**
-     * Flag this as deliberatly generated catch all that rethrows the
-     * caught exception. This is used for example for generating finally
-     * expressions
-     */
-    public void setIsSyntheticRethrow() {
-        this.isSyntheticRethrow = true;
-    }
-
-    /**
      * Get the identifier representing the exception thrown
      * @return the exception identifier
      */
@@ -146,9 +121,13 @@
     /**
      * Reset the exception condition for this catch block
      * @param exceptionCondition the new exception condition
+     * @return new or same CatchNode
      */
-    public void setExceptionCondition(final Node exceptionCondition) {
-        this.exceptionCondition = exceptionCondition;
+    public CatchNode setExceptionCondition(final Node exceptionCondition) {
+        if (this.exceptionCondition == exceptionCondition) {
+            return this;
+        }
+        return new CatchNode(this, exception, exceptionCondition, body);
     }
 
     /**
@@ -158,4 +137,18 @@
     public Block getBody() {
         return body;
     }
+
+    private CatchNode setException(final IdentNode exception) {
+        if (this.exception == exception) {
+            return this;
+        }
+        return new CatchNode(this, exception, exceptionCondition, body);
+    }
+
+    private CatchNode setBody(final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return new CatchNode(this, exception, exceptionCondition, body);
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,43 +25,39 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for CONTINUE statements.
- *
  */
-public class ContinueNode extends LabeledNode {
+@Immutable
+public class ContinueNode extends Node {
+
+    private IdentNode label;
 
     /**
      * Constructor
      *
-     * @param source     the source
-     * @param token      token
-     * @param finish     finish
-     * @param labelNode  the continue label
-     * @param targetNode node to continue to
-     * @param tryChain   surrounding try chain
+     * @param source source code
+     * @param token  token
+     * @param finish finish
+     * @param label  label for break or null if none
      */
-    public ContinueNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) {
-        super(source, token, finish, labelNode, targetNode, tryChain);
-        setHasGoto();
-    }
-
-    private ContinueNode(final ContinueNode continueNode, final CopyState cs) {
-        super(continueNode, cs);
+    public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) {
+        super(source, token, finish);
+        this.label = label;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new ContinueNode(this, cs);
+    public boolean hasGoto() {
+        return true;
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterContinueNode(this) != null) {
+        if (visitor.enterContinueNode(this)) {
             return visitor.leaveContinueNode(this);
         }
 
@@ -69,21 +65,20 @@
     }
 
     /**
-     * Return the target label of this continue node.
-     * @return the target label.
+     * Get the label for this break node
+     * @return label, or null if none
      */
-    public Label getTargetLabel() {
-        assert targetNode instanceof WhileNode : "continue target must be a while node";
-        return ((WhileNode)targetNode).getContinueLabel();
+    public IdentNode getLabel() {
+        return label;
     }
 
     @Override
     public void toString(final StringBuilder sb) {
         sb.append("continue");
 
-        if (labelNode != null) {
+        if (label != null) {
             sb.append(' ');
-            labelNode.getLabel().toString(sb);
+            label.toString(sb);
         }
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/DoWhileNode.java	Wed May 08 11:22:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +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.ir;
-
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * Loop representing do while loops. This is mostly split from WhileNode
- * because of the different order of the Phi Traversals
- *
- */
-public class DoWhileNode extends WhileNode {
-
-    /**
-     * Constructor
-     *
-     * @param source     the source
-     * @param token      token
-     * @param finish     finish
-     */
-    public DoWhileNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
-    }
-
-    /**
-     * Copy constructor
-     *
-     * @param doWhileNode source node
-     * @param cs          copy state
-     */
-    protected DoWhileNode(final DoWhileNode doWhileNode, final CopyState cs) {
-        super(doWhileNode, cs);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new DoWhileNode(this, cs);
-    }
-
-    @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterDoWhileNode(this) != null) {
-            body = (Block)body.accept(visitor);
-            test = test.accept(visitor);
-
-            return visitor.leaveDoWhileNode(this);
-        }
-
-        return this;
-    }
-
-    @Override
-    public void toString(final StringBuilder sb) {
-        sb.append("while (");
-        test.toString(sb);
-        sb.append(')');
-    }
-}
--- a/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,14 +25,15 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an empty statement.
- *
  */
-public class EmptyNode extends Node {
+@Immutable
+public final class EmptyNode extends Node {
 
     /**
      * Constructor
@@ -57,7 +58,7 @@
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterEmptyNode(this) != null) {
+        if (visitor.enterEmptyNode(this)) {
             return visitor.leaveEmptyNode(this);
         }
         return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
@@ -33,9 +34,10 @@
  * node means "this code will be executed" and evaluating it results in
  * statements being added to the IR
  */
-public class ExecuteNode extends Node {
+@Immutable
+public final class ExecuteNode extends Node {
     /** Expression to execute. */
-    private Node expression;
+    private final Node expression;
 
     /**
      * Constructor
@@ -50,6 +52,11 @@
         this.expression = expression;
     }
 
+    private ExecuteNode(final ExecuteNode executeNode, final Node expression) {
+        super(executeNode);
+        this.expression = expression;
+    }
+
     /**
      * Constructor
      *
@@ -60,34 +67,15 @@
         this.expression = expression;
     }
 
-    private ExecuteNode(final ExecuteNode executeNode, final CopyState cs) {
-        super(executeNode);
-        this.expression = cs.existingOrCopy(executeNode.expression);
-    }
-
     @Override
-    protected Node copy(final CopyState cs) {
-        return new ExecuteNode(this, cs);
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        return expression.equals(((ExecuteNode)other).getExpression());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ expression.hashCode();
+    public boolean isTerminal() {
+        return expression.isTerminal();
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterExecuteNode(this) != null) {
-            setExpression(expression.accept(visitor));
-            return visitor.leaveExecuteNode(this);
+        if (visitor.enterExecuteNode(this)) {
+            return visitor.leaveExecuteNode(setExpression(expression.accept(visitor)));
         }
 
         return this;
@@ -109,8 +97,12 @@
     /**
      * Reset the expression to be executed
      * @param expression the expression
+     * @return new or same execute node
      */
-    public void setExpression(final Node expression) {
-        this.expression = expression;
+    public ExecuteNode setExpression(final Node expression) {
+        if (this.expression == expression) {
+            return this;
+        }
+        return new ExecuteNode(this, expression);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/Flags.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.ir;
+
+/**
+ * Interface implemented by all nodes that have flags in
+ * a lexical context. This is needed as we sometimes have to save
+ * the setting of flags in the lexical context until a block
+ * is completely finished and its final version (after multiple
+ * copy on writes) is placed in the lexical context
+ *
+ * @param <T> lexical context node that can have flags set during code generation
+ */
+public interface Flags<T extends LexicalContextNode> {
+
+    /**
+     * Check if a flag is set in a lexical context node
+     * @param flag flag to check
+     * @return flags
+     */
+    public boolean getFlag(int flag);
+
+    /**
+     * Clear a flag of a LexicalContextNode
+     * @param lc lexical context
+     * @param flag flag to clear
+     * @return the new LexicalContext node if flags were changed, same otherwise
+     */
+    public T clearFlag(final LexicalContext lc, int flag);
+
+    /**
+     * Set a flag of a LexicalContextNode
+     * @param lc lexical context
+     * @param flag flag to set
+     * @return the new LexicalContext node if flags were changed, same otherwise
+     */
+    public T setFlag(final LexicalContext lc, int flag);
+
+    /**
+     * Set all flags of a LexicalContextNode, overwriting previous flags
+     * @param lc lexical context
+     * @param flags new flags value
+     * @return the new LexicalContext node if flags were changed, same otherwise
+     */
+    public T setFlags(final LexicalContext lc, int flags);
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,73 +25,75 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representing a FOR statement.
- *
  */
-public class ForNode extends WhileNode {
+@Immutable
+public final class ForNode extends LoopNode {
     /** Initialize expression. */
-    private Node init;
+    private final Node init;
 
     /** Test expression. */
-    private Node modify;
+    private final Node modify;
 
     /** Iterator symbol. */
     private Symbol iterator;
 
-    /** is for in */
-    private boolean isForIn;
+    /** Is this a normal for loop? */
+    public static final int IS_FOR      = 1 << 0;
 
-    /** is for each */
-    private boolean isForEach;
+    /** Is this a normal for in loop? */
+    public static final int IS_FOR_IN   = 1 << 1;
+
+    /** Is this a normal for each in loop? */
+    public static final int IS_FOR_EACH = 1 << 2;
+
+    private final int flags;
 
     /**
      * Constructor
      *
-     * @param source     the source
-     * @param token      token
-     * @param finish     finish
+     * @param source the source
+     * @param token  token
+     * @param finish finish
+     * @param init   init
+     * @param test   test
+     * @param body   body
+     * @param modify modify
+     * @param flags  flags
      */
-    public ForNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
+    public ForNode(final Source source, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) {
+        super(source, token, finish, test, body, false);
+        this.init   = init;
+        this.modify = modify;
+        this.flags  = flags;
     }
 
-    private ForNode(final ForNode forNode, final CopyState cs) {
-        super(forNode, cs);
-
-        this.init      = cs.existingOrCopy(forNode.init);
-        this.modify    = cs.existingOrCopy(forNode.modify);
-        this.iterator  = forNode.iterator;
-        this.isForIn   = forNode.isForIn;
-        this.isForEach = forNode.isForEach;
+    private ForNode(final ForNode forNode, final Node init, final Node test, final Block body, final Node modify, final int flags, final boolean controlFlowEscapes) {
+        super(forNode, test, body, controlFlowEscapes);
+        this.init   = init;
+        this.modify = modify;
+        this.flags  = flags;
+        this.iterator = forNode.iterator; //TODO is this acceptable? symbols are never cloned, just copied as references
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new ForNode(this, cs);
+    public Node ensureUniqueLabels(LexicalContext lc) {
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
     }
 
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterForNode(this) != null) {
-            if (init != null) {
-                init = init.accept(visitor);
-            }
-
-            if (test != null) {
-                test = test.accept(visitor);
-            }
-
-            if (modify != null) {
-                modify = modify.accept(visitor);
-            }
-
-            body = (Block)body.accept(visitor);
-
-            return visitor.leaveForNode(this);
+    protected Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterForNode(this)) {
+            return visitor.leaveForNode(
+                setInit(lc, init == null ? null : init.accept(visitor)).
+                setTest(lc, test == null ? null : test.accept(visitor)).
+                setModify(lc, modify == null ? null : modify.accept(visitor)).
+                setBody(lc, (Block)body.accept(visitor)));
         }
 
         return this;
@@ -122,6 +124,19 @@
         sb.append(')');
     }
 
+    @Override
+    public boolean hasGoto() {
+        return !isForIn() && test == null;
+    }
+
+    @Override
+    public boolean mustEnter() {
+        if (isForIn()) {
+            return false; //may be an empty set to iterate over, then we skip the loop
+        }
+        return test == null;
+    }
+
     /**
      * Get the initialization expression for this for loop
      * @return the initialization expression
@@ -132,10 +147,15 @@
 
     /**
      * Reset the initialization expression for this for loop
+     * @param lc lexical context
      * @param init new initialization expression
+     * @return new for node if changed or existing if not
      */
-    public void setInit(final Node init) {
-        this.init = init;
+    public ForNode setInit(final LexicalContext lc, final Node init) {
+        if (this.init == init) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
     }
 
     /**
@@ -143,14 +163,16 @@
      * @return true if this is a for in constructor
      */
     public boolean isForIn() {
-        return isForIn;
+        return (flags & IS_FOR_IN) != 0;
     }
 
     /**
      * Flag this to be a for in construct
+     * @param lc lexical context
+     * @return new for node if changed or existing if not
      */
-    public void setIsForIn() {
-        this.isForIn = true;
+    public ForNode setIsForIn(final LexicalContext lc) {
+        return setFlags(lc, flags | IS_FOR_IN);
     }
 
     /**
@@ -159,14 +181,16 @@
      * @return true if this is a for each construct
      */
     public boolean isForEach() {
-        return isForEach;
+        return (flags & IS_FOR_EACH) != 0;
     }
 
     /**
      * Flag this to be a for each construct
+     * @param lc lexical context
+     * @return new for node if changed or existing if not
      */
-    public void setIsForEach() {
-        this.isForEach = true;
+    public ForNode setIsForEach(final LexicalContext lc) {
+        return setFlags(lc, flags | IS_FOR_EACH);
     }
 
     /**
@@ -195,10 +219,15 @@
 
     /**
      * Reset the modification expression for this ForNode
+     * @param lc lexical context
      * @param modify new modification expression
+     * @return new for node if changed or existing if not
      */
-    public void setModify(final Node modify) {
-        this.modify = modify;
+    public ForNode setModify(final LexicalContext lc, final Node modify) {
+        if (this.modify == modify) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
     }
 
     @Override
@@ -207,7 +236,39 @@
     }
 
     @Override
-    public void setTest(final Node test) {
-        this.test = test;
+    public ForNode setTest(final LexicalContext lc, final Node test) {
+        if (this.test == test) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
+    }
+
+    @Override
+    public Block getBody() {
+        return body;
     }
+
+    @Override
+    public ForNode setBody(final LexicalContext lc, final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
+    }
+
+    @Override
+    public ForNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes) {
+        if (this.controlFlowEscapes == controlFlowEscapes) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
+    }
+
+    private ForNode setFlags(final LexicalContext lc, final int flags) {
+        if (this.flags == flags) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes));
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java	Thu May 16 11:47:51 2013 +0100
@@ -30,23 +30,19 @@
 import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Stack;
+import java.util.Set;
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.Compiler;
-import jdk.nashorn.internal.codegen.Frame;
-import jdk.nashorn.internal.codegen.MethodEmitter;
+import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.UserAccessorProperty;
@@ -55,9 +51,11 @@
 /**
  * IR representation for function (or script.)
  */
-public class FunctionNode extends Block {
+@Immutable
+public final class FunctionNode extends LexicalContextNode implements Flags<FunctionNode> {
 
-    private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
+    /** Type used for all FunctionNodes */
+    public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
 
     /** Function kinds */
     public enum Kind {
@@ -90,134 +88,106 @@
         /** method has had its types finalized */
         FINALIZED,
         /** method has been emitted to bytecode */
-        EMITTED,
-        /** code installed in a class loader */
-        INSTALLED
+        EMITTED
     }
 
     /** External function identifier. */
     @Ignore
-    private IdentNode ident;
+    private final IdentNode ident;
+
+    /** The body of the function node */
+    private final Block body;
 
     /** Internal function name. */
-    private String name;
+    private final String name;
 
     /** Compilation unit. */
-    private CompileUnit compileUnit;
-
-    /** Method emitter for current method. */
-    private MethodEmitter method;
+    private final CompileUnit compileUnit;
 
     /** Function kind. */
-    private Kind kind;
+    private final Kind kind;
 
     /** List of parameters. */
-    private List<IdentNode> parameters;
+    private final List<IdentNode> parameters;
 
     /** First token of function. **/
-    private long firstToken;
+    private final long firstToken;
 
     /** Last token of function. **/
-    private long lastToken;
+    private final long lastToken;
 
-    /** Variable frames. */
-    private Frame frames;
+    /** Declared symbols in this function node */
+    @Ignore
+    private final Set<Symbol> declaredSymbols;
 
     /** Method's namespace. */
     private final Namespace namespace;
 
-    /** Node representing current this. */
-    @Ignore
-    private IdentNode thisNode;
-
-    /** Node representing current scope. */
-    @Ignore
-    private IdentNode scopeNode;
-
-    /** Node representing return value. */
-    @Ignore
-    private IdentNode resultNode;
-
-    /** Node representing current arguments. */
-    @Ignore
-    private IdentNode argumentsNode;
-
-    /** Node representing callee */
-    @Ignore
-    private IdentNode calleeNode;
-
-    /** Node representing varargs */
-    @Ignore
-    private IdentNode varArgsNode;
-
-    /** Pending label list. */
-    private final Stack<LabelNode> labelStack;
-
-    /** Pending control list. */
-    private final Stack<Node> controlStack;
-
-    /** VarNode for this function statement */
-    @Ignore //this is explicit code anyway and should not be traversed after lower
-    private VarNode funcVarNode;
-
-    /** Line number for function declaration */
-    @Ignore
-    private LineNumberNode funcVarLineNumberNode;
-
-    /** Initializer var func = __callee__, where applicable */
-    @Ignore
-    private Node selfSymbolInit;
-
     /** Current compilation state */
     @Ignore
     private final EnumSet<CompilationState> compilationState;
 
-    /** Type hints, e.g based on parameters at call site */
-    private final Map<IdentNode, Type> specializedTypes;
-
     /** Function flags. */
-    private int flags;
+    private final int flags;
 
     /** Is anonymous function flag. */
-    private static final int IS_ANONYMOUS                = 1 << 0;
+    public static final int IS_ANONYMOUS                = 1 << 0;
+
     /** Is the function created in a function declaration (as opposed to a function expression) */
-    private static final int IS_DECLARED                 = 1 << 1;
+    public static final int IS_DECLARED                 = 1 << 1;
+
     /** is this a strict mode function? */
-    private static final int IS_STRICT_MODE              = 1 << 2;
+    public static final int IS_STRICT                   = 1 << 2;
+
     /** Does the function use the "arguments" identifier ? */
-    private static final int USES_ARGUMENTS              = 1 << 3;
-    /** Are we lowered ? */
-    private static final int IS_LOWERED                  = 1 << 4;
+    public static final int USES_ARGUMENTS              = 1 << 3;
+
     /** Has this node been split because it was too large? */
-    private static final int IS_SPLIT                    = 1 << 5;
-    /** Does the function call eval? */
-    private static final int HAS_EVAL                    = 1 << 6;
-    /** Does the function contain a with block ? */
-    private static final int HAS_WITH                    = 1 << 7;
-    /** Does a descendant function contain a with or eval? */
-    private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8;
-    /** Does the function define "arguments" identifier as a parameter of nested function name? */
-    private static final int DEFINES_ARGUMENTS           = 1 << 9;
-    /** Does the function need a self symbol? */
-    private static final int NEEDS_SELF_SYMBOL           = 1 << 10;
+    public static final int IS_SPLIT                    = 1 << 4;
+
+    /** Does the function call eval? If it does, then all variables in this function might be get/set by it and it can
+     * introduce new variables into this function's scope too.*/
+    public static final int HAS_EVAL                    = 1 << 5;
+
+    /** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
+    public static final int HAS_NESTED_EVAL = 1 << 6;
+
+    /**
+     * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
+     * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
+     * defining a local variable named "arguments" still requires construction of the Arguments object (see
+     * ECMAScript 5.1 Chapter 10.5).
+     * @see #needsArguments()
+     */
+    public static final int DEFINES_ARGUMENTS           = 1 << 8;
+
     /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
-    private static final int USES_ANCESTOR_SCOPE         = 1 << 11;
+    public static final int USES_ANCESTOR_SCOPE         = 1 << 9;
+
     /** Is this function lazily compiled? */
-    private static final int IS_LAZY                     = 1 << 12;
+    public static final int IS_LAZY                     = 1 << 10;
+
     /** Does this function have lazy, yet uncompiled children */
-    private static final int HAS_LAZY_CHILDREN           = 1 << 13;
+    public static final int HAS_LAZY_CHILDREN           = 1 << 11;
+
     /** Does this function have lazy, yet uncompiled children */
-    private static final int IS_PROGRAM                   = 1 << 14;
+    public static final int IS_PROGRAM                  = 1 << 12;
+
+    /** Does this function have nested declarations? */
+    public static final int HAS_FUNCTION_DECLARATIONS   = 1 << 13;
 
-    /** Does this function or any nested functions contain a with or an eval? */
-    private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
+    /** Does this function or any nested functions contain an eval? */
+    private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
+
     /** Does this function need to store all its variables in scope? */
-    private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
+    private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
+
     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
-    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval.
+
+    /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval.
      *  We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
-    private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN;
+    private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | HAS_LAZY_CHILDREN;
 
     /** What is the return type of this function? */
     private Type returnType = Type.UNKNOWN;
@@ -225,107 +195,77 @@
     /**
      * Constructor
      *
-     * @param source    the source
-     * @param token     token
-     * @param finish    finish
-     * @param namespace the namespace
-     * @param ident     the identifier
-     * @param name      the name of the function
+     * @param source     the source
+     * @param token      token
+     * @param finish     finish
+     * @param firstToken first token of the funtion node (including the function declaration)
+     * @param namespace  the namespace
+     * @param ident      the identifier
+     * @param name       the name of the function
+     * @param parameters parameter list
+     * @param kind       kind of function as in {@link FunctionNode.Kind}
+     * @param flags      initial flags
      */
-    public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) {
+    public FunctionNode(
+        final Source source,
+        final long token,
+        final int finish,
+        final long firstToken,
+        final Namespace namespace,
+        final IdentNode ident,
+        final String name,
+        final List<IdentNode> parameters,
+        final FunctionNode.Kind kind,
+        final int flags) {
         super(source, token, finish);
 
         this.ident             = ident;
         this.name              = name;
-        this.kind              = Kind.NORMAL;
-        this.parameters        = new ArrayList<>();
-        this.firstToken        = token;
+        this.kind              = kind;
+        this.parameters        = parameters;
+        this.firstToken        = firstToken;
         this.lastToken         = token;
         this.namespace         = namespace;
-        this.labelStack        = new Stack<>();
-        this.controlStack      = new Stack<>();
         this.compilationState  = EnumSet.of(CompilationState.INITIALIZED);
-        this.specializedTypes  = new HashMap<>();
+        this.declaredSymbols   = new HashSet<>();
+        this.flags             = flags;
+        this.compileUnit       = null;
+        this.body              = null;
     }
 
-    private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
-        super(functionNode, cs);
-
-        this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident);
-        this.name  = functionNode.name;
-        this.kind  = functionNode.kind;
-
-        this.parameters = new ArrayList<>();
-        for (final IdentNode param : functionNode.getParameters()) {
-            this.parameters.add((IdentNode)cs.existingOrCopy(param));
-        }
+    private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) {
+        super(functionNode);
+        this.flags = flags;
+        this.returnType = returnType;
+        this.compileUnit = compileUnit;
+        this.lastToken = lastToken;
+        this.compilationState = compilationState;
+        this.body  = body;
 
-        this.firstToken        = functionNode.firstToken;
-        this.lastToken         = functionNode.lastToken;
-        this.namespace         = functionNode.getNamespace();
-        this.thisNode          = (IdentNode)cs.existingOrCopy(functionNode.thisNode);
-        this.scopeNode         = (IdentNode)cs.existingOrCopy(functionNode.scopeNode);
-        this.resultNode        = (IdentNode)cs.existingOrCopy(functionNode.resultNode);
-        this.argumentsNode     = (IdentNode)cs.existingOrCopy(functionNode.argumentsNode);
-        this.varArgsNode       = (IdentNode)cs.existingOrCopy(functionNode.varArgsNode);
-        this.calleeNode        = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
-        this.labelStack        = new Stack<>();
-        this.controlStack      = new Stack<>();
-
-        this.flags = functionNode.flags;
-
-        this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
-        /** VarNode for this function statement */
-
-        this.compilationState = EnumSet.copyOf(functionNode.compilationState);
-        this.specializedTypes = new HashMap<>();
+        // the fields below never change - they are final and assigned in constructor
+        this.name = functionNode.name;
+        this.ident = functionNode.ident;
+        this.namespace = functionNode.namespace;
+        this.declaredSymbols = functionNode.declaredSymbols;
+        this.kind  = functionNode.kind;
+        this.parameters = functionNode.parameters;
+        this.firstToken = functionNode.firstToken;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        // deep clone all parent blocks
-        return new FunctionNode(this, cs);
-    }
-
-    @Override
-    public Node accept(final NodeVisitor visitor) {
-        final FunctionNode  saveFunctionNode  = visitor.getCurrentFunctionNode();
-        final Block         saveBlock         = visitor.getCurrentBlock();
-        final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter();
-        final CompileUnit   saveCompileUnit   = visitor.getCurrentCompileUnit();
-
-        visitor.setCurrentFunctionNode(this);
-        visitor.setCurrentBlock(this);
-
-        try {
-            if (visitor.enterFunctionNode(this) != null) {
-                if (ident != null) {
-                    ident = (IdentNode)ident.accept(visitor);
-                }
-
-                for (int i = 0, count = parameters.size(); i < count; i++) {
-                    parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
-                }
-
-                for (int i = 0, count = statements.size(); i < count; i++) {
-                    statements.set(i, statements.get(i).accept(visitor));
-                }
-
-                return visitor.leaveFunctionNode(this);
-            }
-        } finally {
-            visitor.setCurrentBlock(saveBlock);
-            visitor.setCurrentFunctionNode(saveFunctionNode);
-            visitor.setCurrentCompileUnit(saveCompileUnit);
-            visitor.setCurrentMethodEmitter(saveMethodEmitter);
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterFunctionNode(this)) {
+            return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor)));
         }
-
         return this;
     }
 
-    @Override
-    public boolean needsScope() {
-        return super.needsScope() || isProgram();
+    /**
+     * Get the compilation state of this function
+     * @return the compilation state
+     */
+    public EnumSet<CompilationState> getState() {
+        return compilationState;
     }
 
     /**
@@ -357,62 +297,17 @@
      * FunctionNode has been lowered, the compiler will add
      * {@code CompilationState#LOWERED} to the state vector
      *
+     * @param lc lexical context
      * @param state {@link CompilationState} to add
-     */
-    public void setState(final CompilationState state) {
-        compilationState.add(state);
-    }
-
-    /*
-     * Frame management.
-     */
-
-    /**
-     * Push a new block frame.
-     *
-     * @return the new frame
-     */
-    public final Frame pushFrame() {
-        frames = new Frame(frames);
-        return frames;
-    }
-
-    /**
-     * Pop a block frame.
+     * @return function node or a new one if state was changed
      */
-    public final void popFrame() {
-        frames = frames.getPrevious();
-    }
-
-    /**
-     * Create a temporary variable to the current frame.
-     *
-     * @param currentFrame Frame to add to - defaults to current function frame
-     * @param type  Strong type of symbol.
-     * @param node  Primary node to use symbol.
-     *
-     * @return Symbol used.
-     */
-    public Symbol newTemporary(final Frame currentFrame, final Type type, final Node node) {
-        assert currentFrame != null;
-        Symbol symbol = node.getSymbol();
-
-        // If no symbol already present.
-        if (symbol == null) {
-            final String uname = uniqueName(TEMP_PREFIX.tag());
-            symbol = new Symbol(uname, IS_TEMP, type);
-            symbol.setNode(node);
+    public FunctionNode setState(final LexicalContext lc, final CompilationState state) {
+        if (this.compilationState.equals(state)) {
+            return this;
         }
-
-        // Assign a slot if it doesn't have one.
-        if (!symbol.hasSlot()) {
-            currentFrame.addSymbol(symbol);
-        }
-
-        // Set symbol to node.
-        node.setSymbol(symbol);
-
-        return symbol;
+        final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
+        newState.add(state);
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body));
     }
 
     /**
@@ -425,18 +320,6 @@
     }
 
     /**
-     * Add a new temporary variable to the current frame
-     *
-     * @param type Strong type of symbol
-     * @param node Primary node to use symbol
-     *
-     * @return symbol used
-     */
-    public Symbol newTemporary(final Type type, final Node node) {
-        return newTemporary(frames, type, node);
-    }
-
-    /**
      * Create a virtual symbol for a literal.
      *
      * @param literalNode Primary node to use symbol.
@@ -444,9 +327,8 @@
      * @return Symbol used.
      */
     public Symbol newLiteral(final LiteralNode<?> literalNode) {
-        final String uname = uniqueName(LITERAL_PREFIX.tag());
+        final String uname = uniqueName(LITERAL_PREFIX.symbolName());
         final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
-        symbol.setNode(literalNode);
         literalNode.setSymbol(symbol);
 
         return symbol;
@@ -482,29 +364,35 @@
         sb.append(')');
     }
 
+    @Override
+    public boolean getFlag(final int flag) {
+        return (flags & flag) != 0;
+    }
+
+    @Override
+    public FunctionNode setFlags(final LexicalContext lc, int flags) {
+        if (this.flags == flags) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
+    }
+
+    @Override
+    public FunctionNode clearFlag(final LexicalContext lc, final int flag) {
+        return setFlags(lc, flags & ~flag);
+    }
+
+    @Override
+    public FunctionNode setFlag(final LexicalContext lc, final int flag) {
+        return setFlags(lc, flags | flag);
+    }
+
     /**
      * Returns true if the function is the top-level program.
      * @return True if this function node represents the top-level program.
      */
     public boolean isProgram() {
-        return (flags & IS_PROGRAM) != 0;
-    }
-
-    /**
-     * Marks the function as representing the top-level program.
-     */
-    public void setProgram() {
-        flags |= IS_PROGRAM;
-    }
-
-    /**
-     * Get the control stack. Used when parsing to establish nesting depths of
-     * different control structures
-     *
-     * @return the control stack
-     */
-    public Stack<Node> getControlStack() {
-        return controlStack;
+        return getFlag(IS_PROGRAM);
     }
 
     /**
@@ -512,54 +400,7 @@
      * @return true if lazy
      */
     public boolean isLazy() {
-        return (flags & IS_LAZY) != 0;
-    }
-
-    /**
-     * Set if this function should be lazily generated
-     * @param isLazy is lazy
-     */
-    public void setIsLazy(final boolean isLazy) {
-        this.flags = isLazy ? flags | IS_LAZY : flags & ~IS_LAZY;
-    }
-
-    /**
-     * Check if the {@code with} keyword is used in this function
-     *
-     * @return true if {@code with} is used
-     */
-    public boolean hasWith() {
-        return (flags & HAS_WITH) != 0;
-    }
-
-    /**
-     * Flag this function as using the {@code with} keyword
-     * @param ancestors the iterator over functions in this functions's containing lexical context
-     */
-    public void setHasWith(final Iterator<FunctionNode> ancestors) {
-        if(!hasWith()) {
-            this.flags |= HAS_WITH;
-            // with requires scope in parents.
-            // TODO: refine this. with should not force all variables in parents to be in scope, only those that are
-            // actually referenced as identifiers by name
-            markParentForWithOrEval(ancestors);
-        }
-    }
-
-    private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) {
-        // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
-        setNeedsScope();
-
-        if(ancestors.hasNext()) {
-            ancestors.next().setDescendantHasWithOrEval(ancestors);
-        }
-    }
-
-    private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) {
-        if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
-            flags |= HAS_DESCENDANT_WITH_OR_EVAL;
-            markParentForWithOrEval(ancestors);
-        }
+        return getFlag(IS_LAZY);
     }
 
     /**
@@ -568,30 +409,7 @@
      * @return true if {@code eval} is used
      */
     public boolean hasEval() {
-        return (flags & HAS_EVAL) != 0;
-    }
-
-    /**
-     * Flag this function as calling the {@code eval} function
-     * @param ancestors the iterator over functions in this functions's containing lexical context
-     */
-    public void setHasEval(final Iterator<FunctionNode> ancestors) {
-        if(!hasEval()) {
-            this.flags |= HAS_EVAL;
-            markParentForWithOrEval(ancestors);
-        }
-    }
-
-    /**
-     * Test whether this function or any of its nested functions contains a <tt>with</tt> statement
-     * or an <tt>eval</tt> call.
-     *
-     * @see #hasWith()
-     * @see #hasEval()
-     * @return true if this or a nested function contains with or eval
-     */
-    public boolean hasDeepWithOrEval() {
-        return (flags & HAS_DEEP_WITH_OR_EVAL) != 0;
+        return getFlag(HAS_EVAL);
     }
 
     /**
@@ -603,90 +421,11 @@
     }
 
     /**
-     * Set the first token for this function
-     * @param firstToken the first token
-     */
-    public void setFirstToken(final long firstToken) {
-        this.firstToken = firstToken;
-    }
-
-    /**
-     * Returns a list of functions declared by this function. Only includes declared functions, and does not include any
-     * function expressions that might occur in its body.
-     * @return a list of functions declared by this function.
+     * Check whether this function has nested function declarations
+     * @return true if nested function declarations exist
      */
-    public List<FunctionNode> getDeclaredFunctions() {
-        // Note that the function does not have a dedicated list of declared functions, but rather relies on the
-        // invariant that all function declarations are at the beginning of the statement list as VarNode with a
-        // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a
-        // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors.
-        final List<FunctionNode> fns = new ArrayList<>();
-        for (final Node stmt : statements) {
-            if(stmt instanceof LineNumberNode) {
-                continue;
-            } else if(stmt instanceof VarNode) {
-                final Node init = ((VarNode)stmt).getInit();
-                if(init instanceof FunctionNode) {
-                    final FunctionNode fn = (FunctionNode)init;
-                    if(fn.isDeclared()) {
-                        fns.add(fn);
-                        continue;
-                    }
-                }
-            }
-            // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are
-            // at the start of the function, we've reached the end of function declarations.
-            break;
-        }
-        return fns;
-    }
-
-    /**
-     * Get the label stack. This is used by the parser to establish
-     * label nesting depth
-     *
-     * @return the label stack
-     */
-    public Stack<LabelNode> getLabelStack() {
-        return labelStack;
-    }
-
-    /**
-     * If this function needs to use var args, return the identifier to the node used
-     * for the var args structure
-     *
-     * @return IdentNode representing the var args structure
-     */
-    public IdentNode getVarArgsNode() {
-        return varArgsNode;
-    }
-
-    /**
-     * Set the identifier to the node used for the var args structure
-     *
-     * @param varArgsNode IdentNode representing the var args
-     */
-    public void setVarArgsNode(final IdentNode varArgsNode) {
-        this.varArgsNode = varArgsNode;
-    }
-
-    /**
-     * If this function uses the {@code callee} variable, return the node used
-     * as this variable
-     *
-     * @return an IdentNode representing the {@code callee} variable
-     */
-    public IdentNode getCalleeNode() {
-        return calleeNode;
-    }
-
-    /**
-     * If this function uses the {@code callee} variable, set the node representing the
-     * callee
-     * @param calleeNode an IdentNode representing the callee
-     */
-    public void setCalleeNode(final IdentNode calleeNode) {
-        this.calleeNode = calleeNode;
+    public boolean hasDeclaredFunctions() {
+        return getFlag(HAS_FUNCTION_DECLARATIONS);
     }
 
     /**
@@ -697,26 +436,7 @@
      * @return true if the function's generated Java method needs a {@code callee} parameter.
      */
     public boolean needsCallee() {
-        return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode());
-    }
-
-    /**
-     * If this is a function where {@code arguments} is used, return the node used as the {@code arguments}
-     * variable
-     * @return an IdentNode representing {@code arguments}
-     */
-    public IdentNode getArgumentsNode() {
-        return argumentsNode;
-    }
-
-    /**
-     * If this is a Function where {@code arguments} is used, an identifier to the node representing
-     * the {@code arguments} value has to be supplied by the compiler
-     *
-     * @param argumentsNode IdentNode that represents {@code arguments}
-     */
-    public void setArgumentsNode(final IdentNode argumentsNode) {
-        this.argumentsNode = argumentsNode;
+        return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrict());
     }
 
     /**
@@ -728,11 +448,42 @@
     }
 
     /**
-     * Reset the identifier for this function
-     * @param ident IdentNode for new identifier
+     * Return a set of symbols declared in this function node. This
+     * is only relevant after Attr, otherwise it will be an empty
+     * set as no symbols have been introduced
+     * @return set of declared symbols in function
+     */
+    public Set<Symbol> getDeclaredSymbols() {
+        return Collections.unmodifiableSet(declaredSymbols);
+    }
+
+    /**
+     * Add a declared symbol to this function node
+     * @param symbol symbol that is declared
      */
-    public void setIdent(final IdentNode ident) {
-        this.ident = ident;
+    public void addDeclaredSymbol(final Symbol symbol) {
+        declaredSymbols.add(symbol);
+    }
+
+    /**
+     * Get the function body
+     * @return the function body
+     */
+    public Block getBody() {
+        return body;
+    }
+
+    /**
+     * Reset the function body
+     * @param lc lexical context
+     * @param body new body
+     * @return new function node if body changed, same if not
+     */
+    public FunctionNode setBody(final LexicalContext lc, final Block body) {
+        if(this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
     }
 
     /**
@@ -748,17 +499,6 @@
     }
 
     /**
-     * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
-     * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
-     * defining a local variable named "arguments" still requires construction of the Arguments object (see
-     * ECMAScript 5.1 Chapter 10.5).
-     * @see #needsArguments()
-     */
-    public void setDefinesArguments() {
-        this.flags |= DEFINES_ARGUMENTS;
-    }
-
-    /**
      * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments".
      * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function
      * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that
@@ -770,15 +510,7 @@
     public boolean needsArguments() {
         // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
         // for top-level script, "arguments" is picked up from Context by Global.init() instead.
-        return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram();
-    }
-
-    /**
-     * Flags this function as one that uses the "arguments" identifier.
-     * @see #needsArguments()
-     */
-    public void setUsesArguments() {
-        flags |= USES_ARGUMENTS;
+        return getFlag(MAYBE_NEEDS_ARGUMENTS) && !getFlag(DEFINES_ARGUMENTS) && !isProgram();
     }
 
     /**
@@ -789,7 +521,7 @@
      * @return true if the function needs parent scope.
      */
     public boolean needsParentScope() {
-        return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram();
+        return getFlag(NEEDS_PARENT_SCOPE) || isProgram();
     }
 
     /**
@@ -802,15 +534,6 @@
     }
 
     /**
-     * Set the kind of this function
-     * @see FunctionNode.Kind
-     * @param kind the kind
-     */
-    public void setKind(final Kind kind) {
-        this.kind = kind;
-    }
-
-    /**
      * Return the last token for this function's code
      * @return last token
      */
@@ -820,10 +543,15 @@
 
     /**
      * Set the last token for this function's code
+     * @param lc lexical context
      * @param lastToken the last token
+     * @return function node or a new one if state was changed
      */
-    public void setLastToken(final long lastToken) {
-        this.lastToken = lastToken;
+    public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
+        if (this.lastToken == lastToken) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
     }
 
     /**
@@ -835,21 +563,13 @@
     }
 
     /**
-     * Set the name of this function
-     * @param name the name
-     */
-    public void setName(final String name) {
-        this.name = name;
-    }
-
-    /**
      * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
      * functions having with and/or eval blocks are such.
      *
      * @return true if all variables should be in scope
      */
     public boolean allVarsInScope() {
-        return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
+        return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE);
     }
 
     /**
@@ -858,15 +578,7 @@
      * @return true if this function is split from a larger one
      */
     public boolean isSplit() {
-        return (flags & IS_SPLIT) != 0;
-    }
-
-    /**
-     * Flag this function node as being a sub-function generated by the splitter
-     */
-    public void setIsSplit() {
-        this.flags |= IS_SPLIT;
-        setNeedsScope();
+        return getFlag(IS_SPLIT);
     }
 
     /**
@@ -875,15 +587,7 @@
      * @return true if there are lazy child functions
      */
     public boolean hasLazyChildren() {
-        return (flags & HAS_LAZY_CHILDREN) != 0;
-    }
-
-    /**
-     * Flag this function node as having yet-to-be-generated child functions
-     */
-    public void setHasLazyChildren() {
-        this.flags |= HAS_LAZY_CHILDREN;
-        setNeedsScope();
+        return getFlag(HAS_LAZY_CHILDREN);
     }
 
     /**
@@ -895,66 +599,13 @@
     }
 
     /**
-     * Set the paremeters to this function
-     * @param parameters a list of IdentNodes representing parameters in left to right order
-     */
-    public void setParameters(final List<IdentNode> parameters) {
-        this.parameters = parameters;
-    }
-
-    /**
      * Get a specialized type for an identity, if one exists
      * @param node node to check specialized type for
      * @return null if no specialization exists, otherwise type
      */
+    @SuppressWarnings("static-method")
     public Type getSpecializedType(final IdentNode node) {
-        return specializedTypes.get(node);
-    }
-
-    /**
-     * Set parameter type hints for specialization.
-     * @param types types array of length equal to parameter list size
-     */
-    public void setParameterTypes(final Class<?>[] types) {
-        assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types";
-        //diff - skip the callee and this etc, they are not explicit params in the parse tree
-        for (int i = 0; i < types.length ; i++) {
-            specializedTypes.put(parameters.get(i), Type.typeFor(types[i]));
-        }
-    }
-
-    /**
-     * Get the identifier for the variable in which the function return value
-     * should be stored
-     * @return an IdentNode representing the return value
-     */
-    public IdentNode getResultNode() {
-        return resultNode;
-    }
-
-    /**
-     * Set the identifier representing the variable in which the function return
-     * value should be stored
-     * @param resultNode an IdentNode representing the return value
-     */
-    public void setResultNode(final IdentNode resultNode) {
-        this.resultNode = resultNode;
-    }
-
-    /**
-     * Get the identifier representing this function's scope
-     * @return an IdentNode representing this function's scope
-     */
-    public IdentNode getScopeNode() {
-        return scopeNode;
-    }
-
-    /**
-     * Set the identifier representing this function's scope
-     * @param scopeNode an IdentNode representing this function's scope
-     */
-    public void setScopeNode(final IdentNode scopeNode) {
-        this.scopeNode = scopeNode;
+        return null; //TODO implement specialized types later
     }
 
     /**
@@ -962,15 +613,7 @@
      * @return true if function is declared.
      */
     public boolean isDeclared() {
-        return (flags & IS_DECLARED) != 0;
-    }
-
-    /**
-     * Flag this function as being created as a function declaration (as opposed to a function expression).
-     * @see Parser
-     */
-    public void setIsDeclared() {
-        this.flags |= IS_DECLARED;
+        return getFlag(IS_DECLARED);
     }
 
     /**
@@ -978,15 +621,7 @@
      * @return true if function is anonymous
      */
     public boolean isAnonymous() {
-        return (flags & IS_ANONYMOUS) != 0;
-    }
-
-    /**
-     * Flag this function as an anonymous function.
-     * @see Parser
-     */
-    public void setIsAnonymous() {
-        this.flags |= IS_ANONYMOUS;
+        return getFlag(IS_ANONYMOUS);
     }
 
     /**
@@ -995,109 +630,7 @@
      * @return true if function needs a symbol for self
      */
     public boolean needsSelfSymbol() {
-        return (flags & NEEDS_SELF_SYMBOL) != 0;
-    }
-
-    /**
-     * Get the initializer statement for the __callee__ variable, where applicable
-     * for self references
-     * @return initialization
-     */
-    public Node getSelfSymbolInit() {
-        return this.selfSymbolInit;
-    }
-
-    /**
-     * Flag the function as needing a self symbol. This is needed only for
-     * self referring functions
-     * @param selfSymbolInit initialization expression for self symbol
-     */
-    public void setNeedsSelfSymbol(final Node selfSymbolInit) {
-        this.flags |= NEEDS_SELF_SYMBOL;
-        this.selfSymbolInit = selfSymbolInit;
-    }
-
-    /**
-     * Marks this function as using any of its ancestors' scopes.
-     */
-    public void setUsesAncestorScope() {
-        this.flags |= USES_ANCESTOR_SCOPE;
-    }
-
-    @Override
-    void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) {
-        setUsesAncestorScope();
-        super.setUsesParentScopeSymbol(symbol, ancestors);
-    }
-
-    /**
-     * Return the node representing {@code this} in this function
-     * @return IdentNode representing {@code this}
-     */
-    public IdentNode getThisNode() {
-        return thisNode;
-    }
-
-    /**
-     * Set the node representing {@code this} in this function
-     * @param thisNode identifier representing {@code this}
-     */
-    public void setThisNode(final IdentNode thisNode) {
-        this.thisNode = thisNode;
-    }
-
-    /**
-     * Every function declared as {@code function x()} is internally hoisted
-     * and represented as {@code var x = function()  ... }. This getter returns
-     * the VarNode representing this virtual assignment
-     *
-     * @return the var node emitted for setting this function symbol
-     */
-    public VarNode getFunctionVarNode() {
-        return funcVarNode;
-    }
-
-    /**
-     * Set the virtual VarNode assignment for this function.
-     * @see FunctionNode#getFunctionVarNode()
-     *
-     * @param varNode the virtual var node assignment
-     */
-    public void setFunctionVarNode(final VarNode varNode) {
-        funcVarNode = varNode;
-    }
-
-    /**
-     * The line number information where the function was declared must be propagated
-     * to the virtual {@code var x = function() ... } assignment described in
-     * {@link FunctionNode#getFunctionVarNode()}
-     * This maintains the line number of the declaration
-     *
-     * @return a line number node representing the line this function was declared
-     */
-    public LineNumberNode getFunctionVarLineNumberNode() {
-        return funcVarLineNumberNode;
-    }
-
-    /**
-     * Set the virtual VarNode assignment for this function, along with
-     * a line number node for tracking the original start line of the function
-     * declaration
-     *
-     * @param varNode    the virtual var node assignment
-     * @param lineNumber the line number node for the function declaration
-     */
-    public void setFunctionVarNode(final VarNode varNode, final LineNumberNode lineNumber) {
-        funcVarNode           = varNode;
-        funcVarLineNumberNode = lineNumber;
-    }
-
-    /**
-     * Get the namespace this function uses for its symbols
-     * @return the namespace
-     */
-    public Namespace getNamespace() {
-        return namespace;
+        return body.getFlag(Block.NEEDS_SELF_SYMBOL);
     }
 
     @Override
@@ -1118,47 +651,38 @@
 
     /**
      * Set the function return type
-     *
+     * @param lc lexical context
      * @param returnType new return type
+     * @return function node or a new one if state was changed
      */
-    public void setReturnType(final Type returnType) {
+    public FunctionNode setReturnType(final LexicalContext lc, final Type returnType) {
         //we never bother with object types narrower than objects, that will lead to byte code verification errors
         //as for instance even if we know we are returning a string from a method, the code generator will always
         //treat it as an object, at least for now
-        this.returnType = Type.widest(this.returnType,  returnType.isObject() ? Type.OBJECT : returnType);
-    }
-
-    /**
-     * Set strict mode on or off for this function
-     *
-     * @param isStrictMode true if strict mode should be enabled
-     */
-    public void setStrictMode(final boolean isStrictMode) {
-        flags = isStrictMode ? flags | IS_STRICT_MODE : flags & ~IS_STRICT_MODE;
+        if (this.returnType == returnType) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(
+            lc,
+            this,
+            new FunctionNode(
+                this,
+                lastToken,
+                flags,
+                Type.widest(this.returnType, returnType.isObject() ?
+                    Type.OBJECT :
+                    returnType),
+                compileUnit,
+                compilationState,
+                body));
     }
 
     /**
      * Check if the function is generated in strict mode
      * @return true if strict mode enabled for function
      */
-    public boolean isStrictMode() {
-        return (flags & IS_STRICT_MODE) != 0;
-    }
-
-    /**
-     * Set the lowered state
-     */
-    public void setIsLowered() {
-        flags |= IS_LOWERED;
-    }
-
-    /**
-     * Get the lowered state
-     *
-     * @return true if function is lowered
-     */
-    public boolean isLowered() {
-        return (flags & IS_LOWERED) != 0;
+    public boolean isStrict() {
+        return getFlag(IS_STRICT);
     }
 
     /**
@@ -1173,25 +697,47 @@
     /**
      * Reset the compile unit used to compile this function
      * @see Compiler
+     * @param lc lexical context
      * @param compileUnit the compile unit
+     * @return function node or a new one if state was changed
      */
-    public void setCompileUnit(final CompileUnit compileUnit) {
-        this.compileUnit = compileUnit;
+    public FunctionNode setCompileUnit(final LexicalContext lc, final CompileUnit compileUnit) {
+        if (this.compileUnit == compileUnit) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body));
     }
 
     /**
-     * Return the method emitter used to write bytecode for this function
-     * @return the method emitter
+     * Create a temporary variable to the current frame.
+     *
+     * @param block that needs the temporary
+     * @param type  Strong type of symbol.
+     * @param node  Primary node to use symbol.
+     *
+     * @return Symbol used.
      */
-    public MethodEmitter getMethodEmitter() {
-        return method;
+    public Symbol ensureSymbol(final Block block, final Type type, final Node node) {
+        Symbol symbol = node.getSymbol();
+
+        // If no symbol already present.
+        if (symbol == null) {
+            final String uname = uniqueName(TEMP_PREFIX.symbolName());
+            symbol = new Symbol(uname, IS_TEMP, type);
+            block.putSymbol(uname, symbol);
+            node.setSymbol(symbol);
+        }
+
+        return symbol;
     }
 
     /**
-     * Set the method emitter that is to be used to write bytecode for this function
-     * @param method a method emitter
+     * Get the symbol for a compiler constant, or null if not available (yet)
+     * @param cc compiler constant
+     * @return symbol for compiler constant, or null if not defined yet (for example in Lower)
      */
-    public void setMethodEmitter(final MethodEmitter method) {
-        this.method = method;
+    public Symbol compilerConstant(final CompilerConstants cc) {
+        return body.getExistingSymbol(cc.symbolName());
     }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java	Thu May 16 11:47:51 2013 +0100
@@ -32,13 +32,15 @@
 
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an identifier.
  */
-public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
+@Immutable
+public final class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
     private static final int PROPERTY_NAME    = 1 << 0;
     private static final int INITIALIZED_HERE = 1 << 1;
     private static final int FUNCTION         = 1 << 2;
@@ -47,9 +49,9 @@
     private final String name;
 
     /** Type for a callsite, e.g. X in a get()X or a set(X)V */
-    private Type callSiteType;
+    private final Type callSiteType;
 
-    private byte flags;
+    private final int flags;
 
     /**
      * Constructor
@@ -62,6 +64,15 @@
     public IdentNode(final Source source, final long token, final int finish, final String name) {
         super(source, token, finish);
         this.name = name;
+        this.callSiteType = null;
+        this.flags = 0;
+    }
+
+    private IdentNode(final IdentNode identNode, final String name, final Type callSiteType, final int flags) {
+        super(identNode);
+        this.name = name;
+        this.callSiteType = callSiteType;
+        this.flags = flags;
     }
 
     /**
@@ -71,8 +82,9 @@
      */
     public IdentNode(final IdentNode identNode) {
         super(identNode);
-        this.name  = identNode.getName();
-        this.flags = identNode.flags;
+        this.name         = identNode.getName();
+        this.callSiteType = null;
+        this.flags        = identNode.flags;
     }
 
     @Override
@@ -92,40 +104,15 @@
 
     @Override
     public IdentNode setType(final Type type) {
-        if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
-            ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
-        }
         // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
-        if(this.callSiteType == type) {
+        if (this.callSiteType == type) {
             return this;
         }
-        final IdentNode n = (IdentNode)clone();
-        n.callSiteType = type;
-        return n;
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new IdentNode(this);
-    }
+        if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
+            ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType());
+        }
 
-    /**
-     * Test to see if two IdentNode are the same.
-     *
-     * @param other Other ident.
-     * @return true if the idents are the same.
-     */
-    @Override
-    public boolean equals(final Object other) {
-        if (other instanceof IdentNode) {
-            return name.equals(((IdentNode)other).name);
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return name.hashCode();
+        return new IdentNode(this, name, type, flags);
     }
 
     /**
@@ -135,7 +122,7 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterIdentNode(this) != null) {
+        if (visitor.enterIdentNode(this)) {
             return visitor.leaveIdentNode(this);
         }
 
@@ -147,7 +134,7 @@
         if (hasCallSiteType()) {
             sb.append('{');
             final String desc = getType().getDescriptor();
-            sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
+            sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor());
             sb.append('}');
         }
 
@@ -191,10 +178,10 @@
      * @return a node equivalent to this one except for the requested change.
      */
     public IdentNode setIsPropertyName() {
-        if(isPropertyName()) return this;
-        final IdentNode n = (IdentNode)clone();
-        n.flags |= PROPERTY_NAME;
-        return n;
+        if (isPropertyName()) {
+            return this;
+        }
+        return new IdentNode(this, name, callSiteType, flags | PROPERTY_NAME);
     }
 
     /**
@@ -210,10 +197,10 @@
      * @return a node equivalent to this one except for the requested change.
      */
     public IdentNode setIsInitializedHere() {
-        if(isInitializedHere()) return this;
-        final IdentNode n = (IdentNode)clone();
-        n.flags |= INITIALIZED_HERE;
-        return n;
+        if (isInitializedHere()) {
+            return this;
+        }
+        return new IdentNode(this, name, callSiteType, flags | INITIALIZED_HERE);
     }
 
     /**
@@ -223,7 +210,7 @@
      * @return true if this IdentNode is special
      */
     public boolean isSpecialIdentity() {
-        return name.equals(__DIR__.tag()) || name.equals(__FILE__.tag()) || name.equals(__LINE__.tag());
+        return name.equals(__DIR__.symbolName()) || name.equals(__FILE__.symbolName()) || name.equals(__LINE__.symbolName());
     }
 
     @Override
@@ -236,9 +223,9 @@
      * @return an ident node identical to this one in all aspects except with its function flag set.
      */
     public IdentNode setIsFunction() {
-        if(isFunction()) return this;
-        final IdentNode n = (IdentNode)clone();
-        n.flags |= FUNCTION;
-        return n;
+        if (isFunction()) {
+            return this;
+        }
+        return new IdentNode(this, name, callSiteType, flags | FUNCTION);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/IfNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IfNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,22 +25,23 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for an IF statement.
- *
  */
-public class IfNode extends Node {
+@Immutable
+public final class IfNode extends Node {
     /** Test expression. */
-    private Node test;
+    private final Node test;
 
     /** Pass statements. */
-    private Block pass;
+    private final Block pass;
 
     /** Fail statements. */
-    private Block fail;
+    private final Block fail;
 
     /**
      * Constructor
@@ -54,37 +55,30 @@
      */
     public IfNode(final Source source, final long token, final int finish, final Node test, final Block pass, final Block fail) {
         super(source, token, finish);
+        this.test = test;
+        this.pass = pass;
+        this.fail = fail;
+    }
 
+    private IfNode(final IfNode ifNode, final Node test, final Block pass, final Block fail) {
+        super(ifNode);
         this.test = test;
         this.pass = pass;
         this.fail = fail;
     }
 
-    private IfNode(final IfNode ifNode, final CopyState cs) {
-        super(ifNode);
-
-        this.test = cs.existingOrCopy(ifNode.test);
-        this.pass = (Block)cs.existingOrCopy(ifNode.pass);
-        this.fail = (Block)cs.existingOrCopy(ifNode.fail);
-    }
-
     @Override
-    protected Node copy(final CopyState cs) {
-        return new IfNode(this, cs);
+    public boolean isTerminal() {
+        return pass.isTerminal() && fail != null && fail.isTerminal();
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterIfNode(this) != null) {
-            test = test.accept(visitor);
-
-            pass = (Block)pass.accept(visitor);
-
-            if (fail != null) {
-                fail = (Block)fail.accept(visitor);
-            }
-
-            return visitor.leaveIfNode(this);
+        if (visitor.enterIfNode(this)) {
+            return visitor.leaveIfNode(
+                setTest(test.accept(visitor)).
+                setPass((Block)pass.accept(visitor)).
+                setFail(fail == null ? null : (Block)fail.accept(visitor)));
         }
 
         return this;
@@ -105,6 +99,13 @@
         return fail;
     }
 
+    private IfNode setFail(final Block fail) {
+        if (this.fail == fail) {
+            return this;
+        }
+        return new IfNode(this, test, pass, fail);
+    }
+
     /**
      * Get the then block for this IfNode
      * @return the then block
@@ -113,6 +114,13 @@
         return pass;
     }
 
+    private IfNode setPass(final Block pass) {
+        if (this.pass == pass) {
+            return this;
+        }
+        return new IfNode(this, test, pass, fail);
+    }
+
     /**
      * Get the test expression for this IfNode
      * @return the test expression
@@ -124,8 +132,12 @@
     /**
      * Reset the test expression for this IfNode
      * @param test a new test expression
+     * @return new or same IfNode
      */
-    public void setTest(final Node test) {
-        this.test = test;
+    public IfNode setTest(final Node test) {
+        if (this.test == test) {
+            return this;
+        }
+        return new IfNode(this, test, pass, fail);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,22 +25,18 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an indexed access (brackets operator.)
- *
  */
-public class IndexNode extends BaseNode implements TypeOverride<IndexNode> {
-    /** Property ident. */
-    private Node index;
-
-    private boolean hasCallSiteType;
+@Immutable
+public final class IndexNode extends BaseNode {
+    /** Property index. */
+    private final Node index;
 
     /**
      * Constructors
@@ -52,50 +48,27 @@
      * @param index   index for access
      */
     public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) {
-        super(source, token, finish, base);
-
+        super(source, token, finish, base, false, false);
         this.index = index;
     }
 
-    /**
-     * Copy constructor
-     *
-     * @param indexNode source node
-     */
-    public IndexNode(final IndexNode indexNode) {
-        this(indexNode, new CopyState());
-    }
-
-    private IndexNode(final IndexNode indexNode, final CopyState cs) {
-        super(indexNode, cs);
-
-        index = cs.existingOrCopy(indexNode.index);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new IndexNode(this, cs);
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        return index.equals(((IndexNode)other).getIndex());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ getIndex().hashCode();
+    private IndexNode(final IndexNode indexNode, final Node base, final Node index, final boolean isFunction, final boolean hasCallSiteType) {
+        super(indexNode, base, isFunction, hasCallSiteType);
+        this.index = index;
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterIndexNode(this) != null) {
-            base = base.accept(visitor);
-            index = index.accept(visitor);
-            return visitor.leaveIndexNode(this);
+        if (visitor.enterIndexNode(this)) {
+            final Node      newBase  = base.accept(visitor);
+            final Node      newIndex = index.accept(visitor);
+            final IndexNode newNode;
+            if (newBase != base || newIndex != index) {
+                newNode = new IndexNode(this, newBase, newIndex, isFunction(), hasCallSiteType());
+            } else {
+                newNode = this;
+            }
+            return visitor.leaveIndexNode(newNode);
         }
 
         return this;
@@ -105,7 +78,7 @@
     public void toString(final StringBuilder sb) {
         final boolean needsParen = tokenType().needsParens(base.tokenType(), true);
 
-        if (hasCallSiteType) {
+        if (hasCallSiteType()) {
             sb.append('{');
             final String desc = getType().getDescriptor();
             sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor());
@@ -135,27 +108,19 @@
         return index;
     }
 
-    /**
-     * Reset the index expression for this IndexNode
-     * @param index a new index expression
-     */
-    public void setIndex(final Node index) {
-        this.index = index;
+    @Override
+    public BaseNode setIsFunction() {
+        if (isFunction()) {
+            return this;
+        }
+        return new IndexNode(this, base, index, true, hasCallSiteType());
     }
 
     @Override
     public IndexNode setType(final Type type) {
-        if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
-            ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
-        }
-        hasCallSiteType = true;
-        getSymbol().setTypeOverride(type);
-        return this;
-    }
-
-    @Override
-    public boolean canHaveCallSiteType() {
-        return true; //carried by the symbol and always the same nodetype==symboltype
+        logTypeChange(type);
+        getSymbol().setTypeOverride(type); //always a temp so this is fine.
+        return new IndexNode(this, base, index, isFunction(), true);
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,29 +25,20 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a labeled statement.
- *
  */
-
-public class LabelNode extends Node {
+@Immutable
+public final class LabelNode extends LexicalContextNode {
     /** Label ident. */
-    private IdentNode label;
+    private final IdentNode label;
 
     /** Statements. */
-    private Block body;
-
-    /** Node to break from. */
-    @Ignore
-    private Node breakNode;
-
-    /** Node to continue. */
-    @Ignore
-    private Node continueNode;
+    private final Block body;
 
     /**
      * Constructor
@@ -65,26 +56,23 @@
         this.body  = body;
     }
 
-    private LabelNode(final LabelNode labelNode, final CopyState cs) {
+    private LabelNode(final LabelNode labelNode, final IdentNode label, final Block body) {
         super(labelNode);
-
-        this.label        = (IdentNode)cs.existingOrCopy(labelNode.label);
-        this.body         = (Block)cs.existingOrCopy(labelNode.body);
-        this.breakNode    = cs.existingOrSame(labelNode.breakNode);
-        this.continueNode = cs.existingOrSame(labelNode.continueNode);
+        this.label = label;
+        this.body  = body;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new LabelNode(this, cs);
+    public boolean isTerminal() {
+        return body.isTerminal();
     }
 
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterLabelNode(this) != null) {
-            label = (IdentNode)label.accept(visitor);
-            body  = (Block)body.accept(visitor);
-            return visitor.leaveLabelNode(this);
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterLabelNode(this)) {
+            return visitor.leaveLabelNode(
+                setLabel(visitor.getLexicalContext(), (IdentNode)label.accept(visitor)).
+                setBody(visitor.getLexicalContext(), (Block)body.accept(visitor)));
         }
 
         return this;
@@ -106,44 +94,15 @@
 
     /**
      * Reset the body of the node
+     * @param lc lexical context
      * @param body new body
-     */
-    public void setBody(final Block body) {
-        this.body = body;
-    }
-
-    /**
-     * Get the break node for this node
-     * @return the break node
-     */
-    public Node getBreakNode() {
-        return breakNode;
-    }
-
-    /**
-     * Reset the break node for this node
-     * @param breakNode the break node
+     * @return new for node if changed or existing if not
      */
-    public void setBreakNode(final Node breakNode) {
-        assert breakNode instanceof BreakableNode || breakNode instanceof Block : "Invalid break node: " + breakNode;
-        this.breakNode = breakNode;
-    }
-
-    /**
-     * Get the continue node for this node
-     * @return the continue node
-     */
-    public Node getContinueNode() {
-        return continueNode;
-    }
-
-    /**
-     * Reset the continue node for this node
-     * @param continueNode the continue node
-     */
-    public void setContinueNode(final Node continueNode) {
-        assert continueNode instanceof WhileNode : "invalid continue node: " + continueNode;
-        this.continueNode = continueNode;
+    public LabelNode setBody(final LexicalContext lc, final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new LabelNode(this, label, body));
     }
 
     /**
@@ -154,4 +113,11 @@
         return label;
     }
 
+    private LabelNode setLabel(final LexicalContext lc, final IdentNode label) {
+        if (this.label == label) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new LabelNode(this, label, body));
+    }
+
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/LabeledNode.java	Wed May 08 11:22:25 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +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.ir;
-
-import jdk.nashorn.internal.ir.annotations.Ignore;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * IR base class for break and continue.
- *
- */
-public abstract class LabeledNode extends Node {
-    /** Optional label. */
-    @Ignore
-    protected final LabelNode labelNode;
-
-    /** Target control node. */
-    @Ignore
-    protected final Node targetNode;
-
-    /** Try chain. */
-    @Ignore
-    protected final TryNode tryChain;
-
-    /** scope nesting level */
-    protected int scopeNestingLevel;
-
-    /**
-     * Constructor
-     *
-     * @param source     the source
-     * @param token      token
-     * @param finish     finish
-     * @param labelNode  the label node
-     * @param targetNode the place to break to
-     * @param tryChain   the try chain
-     */
-    public LabeledNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) {
-        super(source, token, finish);
-
-        this.labelNode  = labelNode;
-        this.targetNode = targetNode;
-        this.tryChain   = tryChain;
-    }
-
-    /**
-     * Copy constructor
-     *
-     * @param labeledNode source node
-     * @param cs          copy state
-     */
-    protected LabeledNode(final LabeledNode labeledNode, final CopyState cs) {
-        super(labeledNode);
-
-        this.labelNode         = (LabelNode)cs.existingOrCopy(labeledNode.labelNode);
-        this.targetNode        = cs.existingOrSame(labeledNode.targetNode);
-        this.tryChain          = (TryNode)cs.existingOrSame(labeledNode.tryChain);
-        this.scopeNestingLevel = labeledNode.scopeNestingLevel;
-    }
-
-    /**
-     * Get the label
-     * @return the label
-     */
-    public LabelNode getLabel() {
-        return labelNode;
-    }
-
-    /**
-     * Get the target node
-     * @return the target node
-     */
-    public Node getTargetNode() {
-        return targetNode;
-    }
-
-    /**
-     * Get the surrounding try chain
-     * @return the try chain
-     */
-    public TryNode getTryChain() {
-        return tryChain;
-    }
-
-    /**
-     * Get the scope nesting level
-     * @return nesting level
-     */
-    public int getScopeNestingLevel() {
-        return scopeNestingLevel;
-    }
-
-    /**
-     * Set scope nesting level
-     * @param level the new level
-     */
-    public void setScopeNestingLevel(final int level) {
-        scopeNestingLevel = level;
-    }
-}
--- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java	Thu May 16 11:47:51 2013 +0100
@@ -1,40 +1,224 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayDeque;
-import java.util.Deque;
+import java.io.File;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
+import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.runtime.Debug;
+import jdk.nashorn.internal.runtime.Source;
 
 /**
  * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special
  * methods to retrieve useful subsets of the context.
+ *
+ * This is implemented with a primitive array and a stack pointer, because it really makes a difference
+ * performance wise. None of the collection classes were optimal
  */
-public class LexicalContext implements Cloneable {
-    private final Deque<Block> lexicalContext;
+public class LexicalContext {
+    private LexicalContextNode[] stack;
+
+    private int[] flags;
+    private int sp;
 
     /**
      * Creates a new empty lexical context.
      */
     public LexicalContext() {
-        lexicalContext = new ArrayDeque<>();
+        stack = new LexicalContextNode[16];
+        flags = new int[16];
+    }
+
+    /**
+     * Set the flags for a lexical context node on the stack. Does not
+     * replace the flags, but rather adds to them
+     *
+     * @param node  node
+     * @param flag  new flag to set
+     */
+    public void setFlag(final LexicalContextNode node, final int flag) {
+        if (flag != 0) {
+            for (int i = sp - 1; i >= 0; i--) {
+                if (stack[i] == node) {
+                    flags[i] |= flag;
+                    //System.err.println("Setting flag " + node + " " + flag);
+                    return;
+                }
+            }
+        }
+        assert false;
     }
 
     /**
+     * Get the flags for a lexical context node on the stack
+     * @param node node
+     * @return the flags for the node
+     */
+    public int getFlags(final LexicalContextNode node) {
+        for (int i = sp - 1; i >= 0; i--) {
+            if (stack[i] == node) {
+                return flags[i];
+            }
+        }
+        throw new AssertionError("flag node not on context stack");
+    }
+
+    /**
+     * Get the function body of a function node on the lexical context
+     * stack. This will trigger an assertion if node isn't present
+     * @param functionNode function node
+     * @return body of function node
+     */
+    public Block getFunctionBody(final FunctionNode functionNode) {
+        for (int i = sp - 1; i >= 0 ; i--) {
+            if (stack[i] == functionNode) {
+                return (Block)stack[i + 1];
+            }
+        }
+        throw new AssertionError(functionNode.getName() + " not on context stack");
+    }
+
+    /**
+     * Return all nodes in the LexicalContext
+     * @return all nodes
+     */
+    public Iterator<LexicalContextNode> getAllNodes() {
+        return new NodeIterator<>(LexicalContextNode.class);
+    }
+
+    /**
+     * Returns the outermost function in this context. It is either the program, or a lazily compiled function.
+     * @return the outermost function in this context.
+     */
+    public FunctionNode getOutermostFunction() {
+        return (FunctionNode)stack[0];
+    }
+
+
+
+    /**
      * Pushes a new block on top of the context, making it the innermost open block.
-     * @param block the new block
+     * @param node the new node
+     * @return the node that was pushed
      */
-    public void push(Block block) {
-        //new Exception(block.toString()).printStackTrace();
-        lexicalContext.push(block);
+    public <T extends LexicalContextNode> T push(final T node) {
+        if (sp == stack.length) {
+            final LexicalContextNode[] newStack = new LexicalContextNode[sp * 2];
+            System.arraycopy(stack, 0, newStack, 0, sp);
+            stack = newStack;
+
+            final int[] newFlags = new int[sp * 2];
+            System.arraycopy(flags, 0, newFlags, 0, sp);
+            flags = newFlags;
+
+        }
+        stack[sp] = node;
+        flags[sp] = 0;
+
+        sp++;
+
+        return node;
+    }
+
+    /**
+     * Is the context empty?
+     * @return true if empty
+     */
+    public boolean isEmpty() {
+        return sp == 0;
+    }
+
+    /**
+     * The depth of the lexical context
+     * @return depth
+     */
+    public int size() {
+        return sp;
     }
 
     /**
-     * Pops the innermost block off the context.
-     * @param the block expected to be popped, used to detect unbalanced pushes/pops
+     * Pops the innermost block off the context and all nodes that has been contributed
+     * since it was put there
+     *
+     * @param node the node expected to be popped, used to detect unbalanced pushes/pops
+     * @return the node that was popped
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends LexicalContextNode> T pop(final T node) {
+        --sp;
+        final LexicalContextNode popped = stack[sp];
+        stack[sp] = null;
+        if (popped instanceof Flags) {
+            return (T)((Flags<?>)popped).setFlag(this, flags[sp]);
+        }
+
+        return (T)popped;
+    }
+
+
+    /**
+     * Return the top element in the context
+     * @return the node that was pushed last
      */
-    public void pop(Block block) {
-        final Block popped = lexicalContext.pop();
-        assert popped == block;
+    public LexicalContextNode peek() {
+        return stack[sp - 1];
+    }
+
+    /**
+     * Check if a node is in the lexical context
+     * @param node node to check for
+     * @return true if in the context
+     */
+    public boolean contains(final LexicalContextNode node) {
+        for (int i = 0; i < sp; i++) {
+            if (stack[i] == node) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Replace a node on the lexical context with a new one. Normally
+     * you should try to engineer IR traversals so this isn't needed
+     *
+     * @param oldNode old node
+     * @param newNode new node
+     * @return the new node
+     */
+    public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) {
+       //System.err.println("REPLACE old=" + Debug.id(oldNode) + " new=" + Debug.id(newNode));
+        for (int i = sp - 1; i >= 0; i--) {
+            if (stack[i] == oldNode) {
+                assert i == (sp - 1) : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it";
+                stack[i] = newNode;
+                break;
+            }
+         }
+        return newNode;
     }
 
     /**
@@ -42,7 +226,7 @@
      * @return an iterator over all blocks in the context.
      */
     public Iterator<Block> getBlocks() {
-        return lexicalContext.iterator();
+        return new NodeIterator<>(Block.class);
     }
 
     /**
@@ -50,47 +234,17 @@
      * @return an iterator over all functions in the context.
      */
     public Iterator<FunctionNode> getFunctions() {
-        return new FunctionIterator(getBlocks());
+        return new NodeIterator<>(FunctionNode.class);
     }
 
-    private static final class FunctionIterator implements Iterator<FunctionNode> {
-        private final Iterator<Block> it;
-        private FunctionNode next;
-
-        FunctionIterator(Iterator<Block> it) {
-            this.it = it;
-            next = findNext();
-        }
-
-        @Override
-        public boolean hasNext() {
-            return next != null;
-        }
-
-        @Override
-        public FunctionNode next() {
-            if(next == null) {
-                throw new NoSuchElementException();
-            }
-            FunctionNode lnext = next;
-            next = findNext();
-            return lnext;
-        }
-
-        private FunctionNode findNext() {
-            while(it.hasNext()) {
-                final Block block = it.next();
-                if(block instanceof FunctionNode) {
-                    return ((FunctionNode)block);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
+    /**
+     * Get the parent block for the current lexical context block
+     * @return parent block
+     */
+    public Block getParentBlock() {
+        final Iterator<Block> iter = new NodeIterator<>(Block.class, getCurrentFunction());
+        iter.next();
+        return iter.hasNext() ? iter.next() : null;
     }
 
     /**
@@ -98,12 +252,12 @@
      * @param block the block whose ancestors are returned
      * @return an iterator over all ancestors block of the given block.
      */
-    public Iterator<Block> getAncestorBlocks(Block block) {
-        final Iterator<Block> it = getBlocks();
-        while(it.hasNext()) {
-            final Block b = it.next();
-            if(block == b) {
-                return it;
+    public Iterator<Block> getAncestorBlocks(final Block block) {
+        final Iterator<Block> iter = getBlocks();
+        while (iter.hasNext()) {
+            final Block b = iter.next();
+            if (block == b) {
+                return iter;
             }
         }
         throw new AssertionError("Block is not on the current lexical context stack");
@@ -115,17 +269,17 @@
      * @return an iterator over a block and all its ancestors.
      */
     public Iterator<Block> getBlocks(final Block block) {
-        final Iterator<Block> it = getAncestorBlocks(block);
+        final Iterator<Block> iter = getAncestorBlocks(block);
         return new Iterator<Block>() {
             boolean blockReturned = false;
             @Override
             public boolean hasNext() {
-                return it.hasNext() || !blockReturned;
+                return iter.hasNext() || !blockReturned;
             }
             @Override
             public Block next() {
-                if(blockReturned) {
-                    return it.next();
+                if (blockReturned) {
+                    return iter.next();
                 }
                 blockReturned = true;
                 return block;
@@ -138,45 +292,25 @@
     }
 
     /**
-     * Returns the closest function node to the block. If the block is itself a function, it is returned.
-     * @param block the block
-     * @return the function closest to the block.
-     * @see #getParentFunction(Block)
-     */
-    public FunctionNode getFunction(Block block) {
-        if(block instanceof FunctionNode) {
-            return (FunctionNode)block;
-        }
-        return getParentFunction(block);
-    }
-
-    /**
-     * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function,
-     * it is returned too.
-     * @param block the block
-     * @return the closest function node to the block and all its ancestor functions.
+     * Get the function for this block. If the block is itself a function
+     * this returns identity
+     * @param block block for which to get function
+     * @return function for block
      */
-    public Iterator<FunctionNode> getFunctions(final Block block) {
-        return new FunctionIterator(getBlocks(block));
-    }
-
-    /**
-     * Returns the containing function of the block. If the block is itself a function, its parent function is returned.
-     * @param block the block
-     * @return the containing function of the block.
-     * @see #getFunction(Block)
-     */
-    public FunctionNode getParentFunction(Block block) {
-        return getFirstFunction(getAncestorBlocks(block));
-    }
-
-    private static FunctionNode getFirstFunction(Iterator<Block> it) {
-        while(it.hasNext()) {
-            final Block ancestor = it.next();
-            if(ancestor instanceof FunctionNode) {
-                return (FunctionNode)ancestor;
+    public FunctionNode getFunction(final Block block) {
+        final Iterator<LexicalContextNode> iter = new NodeIterator<>(LexicalContextNode.class);
+        while (iter.hasNext()) {
+            final LexicalContextNode next = iter.next();
+            if (next == block) {
+                while (iter.hasNext()) {
+                    final LexicalContextNode next2 = iter.next();
+                    if (next2 instanceof FunctionNode) {
+                        return (FunctionNode)next2;
+                    }
+                }
             }
         }
+        assert false;
         return null;
     }
 
@@ -185,7 +319,7 @@
      * @return the innermost block in the context.
      */
     public Block getCurrentBlock() {
-        return lexicalContext.element();
+        return getBlocks().next();
     }
 
     /**
@@ -193,6 +327,284 @@
      * @return the innermost function in the context.
      */
     public FunctionNode getCurrentFunction() {
-        return getFirstFunction(getBlocks());
+        if (isEmpty()) {
+            return null;
+        }
+        return new NodeIterator<>(FunctionNode.class).next();
+    }
+
+    /**
+     * Get the block in which a symbol is defined
+     * @param symbol symbol
+     * @return block in which the symbol is defined, assert if no such block in context
+     */
+    public Block getDefiningBlock(final Symbol symbol) {
+        if (symbol.isTemp()) {
+            return null;
+        }
+        final String name = symbol.getName();
+        for (final Iterator<Block> it = getBlocks(); it.hasNext();) {
+            final Block next = it.next();
+            if (next.getExistingSymbol(name) == symbol) {
+                return next;
+            }
+        }
+        throw new AssertionError("Couldn't find symbol " + name + " in the context");
+    }
+
+    /**
+     * Get the function in which a symbol is defined
+     * @param symbol symbol
+     * @return function node in which this symbol is defined, assert if no such symbol exists in context
+     */
+    public FunctionNode getDefiningFunction(Symbol symbol) {
+        if (symbol.isTemp()) {
+            return null;
+        }
+        final String name = symbol.getName();
+        for (final Iterator<LexicalContextNode> iter = new NodeIterator<>(LexicalContextNode.class); iter.hasNext();) {
+            final LexicalContextNode next = iter.next();
+            if (next instanceof Block && ((Block)next).getExistingSymbol(name) == symbol) {
+                while (iter.hasNext()) {
+                    final LexicalContextNode next2 = iter.next();
+                    if (next2 instanceof FunctionNode) {
+                        return ((FunctionNode)next2);
+                    }
+                }
+                throw new AssertionError("Defining block for symbol " + name + " has no function in the context");
+            }
+        }
+        throw new AssertionError("Couldn't find symbol " + name + " in the context");
+    }
+
+    /**
+     * Is the topmost lexical context element a function body?
+     * @return true if function body
+     */
+    public boolean isFunctionBody() {
+        return getParentBlock() == null;
+    }
+
+    /**
+     * Returns true if the expression defining the function is a callee of a CallNode that should be the second
+     * element on the stack, e.g. <code>(function(){})()</code>. That is, if the stack ends with
+     * {@code [..., CallNode, FunctionNode]} then {@code callNode.getFunction()} should be equal to
+     * {@code functionNode}, and the top of the stack should itself be a variant of {@code functionNode}.
+     * @param functionNode the function node being tested
+     * @return true if the expression defining the current function is a callee of a call expression.
+     */
+    public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) {
+        final LexicalContextNode parent = stack[sp - 2];
+        if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) {
+            assert functionNode.getSource() == peek().getSource();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get the parent function for a function in the lexical context
+     * @param functionNode function for which to get parent
+     * @return parent function of functionNode or null if none (e.g. if functionNode is the program)
+     */
+    public FunctionNode getParentFunction(final FunctionNode functionNode) {
+        final Iterator<FunctionNode> iter = new NodeIterator<>(FunctionNode.class);
+        while (iter.hasNext()) {
+            final FunctionNode next = iter.next();
+            if (next == functionNode) {
+                return iter.hasNext() ? iter.next() : null;
+            }
+        }
+        assert false;
+        return null;
+    }
+
+    /**
+     * Count the number of with scopes until a given node
+     * @param until node to stop counting at, or null if all nodes should be counted
+     * @return number of with scopes encountered in the context
+     */
+    public int getScopeNestingLevelTo(final LexicalContextNode until) {
+        //count the number of with nodes until "until" is hit
+        int n = 0;
+        for (final Iterator<WithNode> iter = new NodeIterator<>(WithNode.class, until); iter.hasNext(); iter.next()) {
+            n++;
+        }
+        return n;
+    }
+
+    private BreakableNode getBreakable() {
+        for (final NodeIterator<BreakableNode> iter = new NodeIterator<>(BreakableNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final BreakableNode next = iter.next();
+            if (next.isBreakableWithoutLabel()) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find the breakable node corresponding to this label.
+     * @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label
+     * @return closest breakable node
+     */
+    public BreakableNode getBreakable(final IdentNode label) {
+        if (label != null) {
+            final LabelNode foundLabel = findLabel(label.getName());
+            if (foundLabel != null) {
+                // iterate to the nearest breakable to the foundLabel
+                BreakableNode breakable = null;
+                for (final NodeIterator<BreakableNode> iter = new NodeIterator<>(BreakableNode.class, foundLabel); iter.hasNext(); ) {
+                    breakable = iter.next();
+                }
+                return breakable;
+            }
+            return null;
+        }
+        return getBreakable();
+    }
+
+    private LoopNode getContinueTo() {
+        final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction());
+        return iter.hasNext() ? iter.next() : null;
+    }
+
+    /**
+     * Find the continue target node corresponding to this label.
+     * @param label label to search for, if null the closest loop node will be returned unconditionally, e.g. a while loop with no label
+     * @return closest continue target node
+     */
+    public LoopNode getContinueTo(final IdentNode label) {
+        if (label != null) {
+            final LabelNode foundLabel = findLabel(label.getName());
+            if (foundLabel != null) {
+                // iterate to the nearest loop to the foundLabel
+                LoopNode loop = null;
+                for (final NodeIterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, foundLabel); iter.hasNext(); ) {
+                    loop = iter.next();
+                }
+                return loop;
+            }
+            return null;
+        }
+        return getContinueTo();
+    }
+
+    /**
+     * Check the lexical context for a given label node by name
+     * @param name name of the label
+     * @return LabelNode if found, null otherwise
+     */
+    public LabelNode findLabel(final String name) {
+        for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) {
+            final LabelNode next = iter.next();
+            if (next.getLabel().getName().equals(name)) {
+                return next;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Checks whether a given label is a jump destination that lies outside a given
+     * split node
+     * @param splitNode the split node
+     * @param label     the label
+     * @return true if label resides outside the split node
+     */
+    public boolean isExternalTarget(final SplitNode splitNode, final Label label) {
+        boolean targetFound = false;
+        for (int i = sp - 1; i >= 0; i--) {
+            final LexicalContextNode next = stack[i];
+            if (next == splitNode) {
+                return !targetFound;
+            }
+
+            if (next instanceof BreakableNode) {
+                for (final Label l : ((BreakableNode)next).getLabels()) {
+                    if (l == label) {
+                        targetFound = true;
+                        break;
+                    }
+                }
+            }
+        }
+        assert false : label + " was expected in lexical context " + LexicalContext.this + " but wasn't";
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer();
+        sb.append("[ ");
+        for (int i = 0; i < sp; i++) {
+            final Node node = stack[i];
+            sb.append(node.getClass().getSimpleName());
+            sb.append('@');
+            sb.append(Debug.id(node));
+            sb.append(':');
+            final Source source = node.getSource();
+            String src = source.toString();
+            if (src.indexOf(File.pathSeparator) != -1) {
+                src = src.substring(src.lastIndexOf(File.pathSeparator));
+            }
+            src += ' ';
+            src += source.getLine(node.getStart());
+            sb.append(' ');
+        }
+        sb.append(" ==> ]");
+        return sb.toString();
+    }
+
+    private class NodeIterator <T extends LexicalContextNode> implements Iterator<T> {
+        private int index;
+        private T next;
+        private final Class<T> clazz;
+        private LexicalContextNode until;
+
+        NodeIterator(final Class<T> clazz) {
+            this(clazz, null);
+        }
+
+        NodeIterator(final Class<T> clazz, final LexicalContextNode until) {
+            this.index = sp - 1;
+            this.clazz = clazz;
+            this.until = until;
+            this.next  = findNext();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public T next() {
+            if (next == null) {
+                throw new NoSuchElementException();
+            }
+            T lnext = next;
+            next = findNext();
+            return lnext;
+        }
+
+        private T findNext() {
+            for (int i = index; i >= 0; i--) {
+                final Node node = stack[i];
+                if (node == until) {
+                    return null;
+                }
+                if (clazz.isAssignableFrom(node.getClass())) {
+                    index = i - 1;
+                    return clazz.cast(node);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,73 @@
+/*
+ * 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.ir;
+
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.runtime.Source;
+
+/**
+ * Superclass for nodes that can be part of the lexical context
+ * @see LexicalContext
+ */
+public abstract class LexicalContextNode extends Node {
+    /**
+     * Constructor
+     *
+     * @param source source
+     * @param token  token
+     * @param finish finish
+     */
+    protected LexicalContextNode(final Source source, final long token, final int finish) {
+        super(source, token, finish);
+    }
+
+    /**
+     * Copy constructor
+     *
+     * @param node source node
+     */
+    protected LexicalContextNode(final LexicalContextNode node) {
+        super(node);
+    }
+
+    /**
+     * Accept function for the node given a lexical context. It must be prepared
+     * to replace itself if present in the lexical context
+     *
+     * @param lc      lexical context
+     * @param visitor node visitor
+     *
+     * @return new node or same node depending on state change
+     */
+    protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor);
+
+    @Override
+    public Node accept(final NodeVisitor visitor) {
+        final LexicalContext lc = visitor.getLexicalContext();
+        lc.push(this);
+        final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor);
+        return lc.pop(newNode);
+    }
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,6 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.runtime.Source;
@@ -32,8 +33,8 @@
 /**
  * IR Node representing a line number
  */
-
-public class LineNumberNode extends Node {
+@Immutable
+public final class LineNumberNode extends Node {
     /** Line number */
     private final int lineNumber;
 
@@ -46,24 +47,17 @@
      */
     public LineNumberNode(final Source source, final long token, final int lineNumber) {
         super(source, token, Token.descPosition(token));
-
         this.lineNumber = lineNumber;
     }
 
-   private LineNumberNode(final LineNumberNode lineNumberNode) {
+    private LineNumberNode(final LineNumberNode lineNumberNode) {
         super(lineNumberNode);
-
         this.lineNumber = lineNumberNode.getLineNumber();
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new LineNumberNode(this);
-    }
-
-    @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterLineNumberNode(this) != null) {
+        if (visitor.enterLineNumberNode(this)) {
             return visitor.leaveLineNumberNode(this);
         }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java	Thu May 16 11:47:51 2013 +0100
@@ -30,6 +30,7 @@
 import java.util.List;
 import jdk.nashorn.internal.codegen.CompileUnit;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Lexer.LexerToken;
 import jdk.nashorn.internal.parser.Token;
@@ -44,6 +45,7 @@
  *
  * @param <T> the literal type
  */
+@Immutable
 public abstract class LiteralNode<T> extends Node implements PropertyKey {
     /** Literal value */
     protected final T value;
@@ -93,23 +95,6 @@
         return value == null;
     }
 
-    @Override
-    public int hashCode() {
-        return value == null ? 0 : value.hashCode();
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!(other instanceof LiteralNode<?>)) {
-            return false;
-        }
-        final LiteralNode<?> otherNode = (LiteralNode<?>)other;
-        if (otherNode.isNull()) {
-            return isNull();
-        }
-        return ((LiteralNode<?>)other).getValue().equals(value);
-    }
-
     /**
      * Check if the literal value is boolean true
      * @return true if literal value is boolean true
@@ -226,7 +211,7 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterLiteralNode(this) != null) {
+        if (visitor.enterLiteralNode(this)) {
             return visitor.leaveLiteralNode(this);
         }
 
@@ -274,7 +259,8 @@
         return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
     }
 
-    private static class BooleanLiteralNode extends LiteralNode<Boolean> {
+    @Immutable
+    private static final class BooleanLiteralNode extends LiteralNode<Boolean> {
 
         private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) {
             super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value);
@@ -285,11 +271,6 @@
         }
 
         @Override
-        protected Node copy(final CopyState cs) {
-            return new BooleanLiteralNode(this);
-        }
-
-        @Override
         public boolean isTrue() {
             return value;
         }
@@ -331,7 +312,8 @@
         return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
     }
 
-    private static class NumberLiteralNode extends LiteralNode<Number> {
+    @Immutable
+    private static final class NumberLiteralNode extends LiteralNode<Number> {
 
         private final Type type = numberGetType(value);
 
@@ -358,11 +340,6 @@
         }
 
         @Override
-        protected Node copy(final CopyState cs) {
-            return new NumberLiteralNode(this);
-        }
-
-        @Override
         public Type getType() {
             return type;
         }
@@ -407,11 +384,6 @@
         private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) {
             super(literalNode);
         }
-
-        @Override
-        protected Node copy(final CopyState cs) {
-            return new UndefinedLiteralNode(this);
-        }
     }
 
     /**
@@ -440,6 +412,7 @@
         return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish());
     }
 
+    @Immutable
     private static class StringLiteralNode extends LiteralNode<String> {
         private StringLiteralNode(final Source source, final long token, final int finish, final String value) {
             super(source, Token.recast(token, TokenType.STRING), finish, value);
@@ -450,11 +423,6 @@
         }
 
         @Override
-        protected Node copy(final CopyState cs) {
-            return new StringLiteralNode(this);
-        }
-
-        @Override
         public void toString(final StringBuilder sb) {
             sb.append('\"');
             sb.append(value);
@@ -488,6 +456,7 @@
         return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
     }
 
+    @Immutable
     private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> {
         private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) {
             super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here?
@@ -498,11 +467,6 @@
         }
 
         @Override
-        protected Node copy(final CopyState cs) {
-            return new LexerTokenLiteralNode(this);
-        }
-
-        @Override
         public Type getType() {
             return Type.OBJECT;
         }
@@ -539,7 +503,7 @@
         return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value);
     }
 
-    private static class NodeLiteralNode extends LiteralNode<Node> {
+    private static final class NodeLiteralNode extends LiteralNode<Node> {
 
         private NodeLiteralNode(final Source source, final long token, final int finish) {
             this(source, token, finish, null);
@@ -558,13 +522,8 @@
         }
 
         @Override
-        protected Node copy(final CopyState cs) {
-            return new NodeLiteralNode(this);
-        }
-
-        @Override
         public Node accept(final NodeVisitor visitor) {
-            if (visitor.enterLiteralNode(this) != null) {
+            if (visitor.enterLiteralNode(this)) {
                 if (value != null) {
                     final Node newValue = value.accept(visitor);
                     if(value != newValue) {
@@ -617,7 +576,7 @@
     /**
      * Array literal node class.
      */
-    public static class ArrayLiteralNode extends LiteralNode<Node[]> {
+    public static final class ArrayLiteralNode extends LiteralNode<Node[]> {
         private static class PostsetMarker {
             //empty
         }
@@ -705,11 +664,6 @@
             this.elementType = node.elementType;
         }
 
-        @Override
-        protected Node copy(final CopyState cs) {
-            return new ArrayLiteralNode(this);
-        }
-
         /**
          * Compute things like widest element type needed. Internal use from compiler only
          */
@@ -894,7 +848,7 @@
 
         @Override
         public Node accept(final NodeVisitor visitor) {
-            if (visitor.enterLiteralNode(this) != null) {
+            if (visitor.enterLiteralNode(this)) {
                 for (int i = 0; i < value.length; i++) {
                     final Node element = value[i];
                     if (element != null) {
--- a/nashorn/src/jdk/nashorn/internal/ir/Location.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/Location.java	Thu May 16 11:47:51 2013 +0100
@@ -25,16 +25,13 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.Objects;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Used to locate an entity back to it's source file.
- *
  */
-
 public class Location implements Cloneable {
     /** Source of entity. */
     private final Source source;
@@ -73,22 +70,13 @@
     }
 
     @Override
-    public boolean equals(final Object other) {
-        if (other == null) {
-            return false;
-        }
-
-        if (other.getClass() != this.getClass()) {
-            return false;
-        }
-
-        final Location loc = (Location)other;
-        return token == loc.token && Objects.equals(source, loc.source);
+    public final boolean equals(final Object other) {
+        return super.equals(other);
     }
 
     @Override
-    public int hashCode() {
-        return Token.hashCode(token) ^ Objects.hashCode(source);
+    public final int hashCode() {
+        return super.hashCode();
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/LoopNode.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,176 @@
+/*
+ * 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.ir;
+
+import java.util.Arrays;
+import java.util.List;
+
+import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.runtime.Source;
+
+/**
+ * A loop node, for example a while node, do while node or for node
+ */
+public abstract class LoopNode extends BreakableNode {
+    /** loop continue label. */
+    protected final Label continueLabel;
+
+    /** Loop test node, null if infinite */
+    protected final Node test;
+
+    /** Loop body */
+    protected final Block body;
+
+    /** Can control flow escape from loop, e.g. through breaks or continues to outer loops? */
+    protected final boolean controlFlowEscapes;
+
+    /**
+     * Constructor
+     *
+     * @param source  source
+     * @param token   token
+     * @param finish  finish
+     * @param test    test, or null if infinite loop
+     * @param body    loop body
+     * @param controlFlowEscapes controlFlowEscapes
+     */
+    protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) {
+        super(source, token, finish, new Label("while_break"));
+        this.continueLabel = new Label("while_continue");
+        this.test = test;
+        this.body = body;
+        this.controlFlowEscapes = controlFlowEscapes;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param loopNode loop node
+     * @param test     new test
+     * @param body     new body
+     * @param controlFlowEscapes controlFlowEscapes
+     */
+    protected LoopNode(final LoopNode loopNode, final Node test, final Block body, final boolean controlFlowEscapes) {
+        super(loopNode);
+        this.continueLabel = new Label(loopNode.continueLabel);
+        this.test = test;
+        this.body = body;
+        this.controlFlowEscapes = controlFlowEscapes;
+    }
+
+    @Override
+    public abstract Node ensureUniqueLabels(final LexicalContext lc);
+
+    /**
+     * Does the control flow escape from this loop, i.e. through breaks or
+     * continues to outer loops?
+     * @return true if control flow escapes
+     */
+    public boolean controlFlowEscapes() {
+        return controlFlowEscapes;
+    }
+
+
+    @Override
+    public boolean isTerminal() {
+        if (!mustEnter()) {
+            return false;
+        }
+        //must enter but control flow may escape - then not terminal
+        if (controlFlowEscapes) {
+            return false;
+        }
+        //must enter, but body ends with return - then terminal
+        if (body.isTerminal()) {
+            return true;
+        }
+        //no breaks or returns, it is still terminal if we can never exit
+        return test == null;
+    }
+
+    /**
+     * Conservative check: does this loop have to be entered?
+     * @return true if body will execute at least once
+     */
+    public abstract boolean mustEnter();
+
+    /**
+     * Get the continue label for this while node, i.e. location to go to on continue
+     * @return continue label
+     */
+    public Label getContinueLabel() {
+        return continueLabel;
+    }
+
+    @Override
+    public List<Label> getLabels() {
+        return Arrays.asList(breakLabel, continueLabel);
+    }
+
+    @Override
+    public boolean isLoop() {
+        return true;
+    }
+
+    /**
+     * Get the body for this for node
+     * @return the body
+     */
+    public abstract Block getBody();
+
+    /**
+     * @param lc   lexical context
+     * @param body new body
+     * @return new for node if changed or existing if not
+     */
+    public abstract LoopNode setBody(final LexicalContext lc, final Block body);
+
+    /**
+     * Get the test for this for node
+     * @return the test
+     */
+    public abstract Node getTest();
+
+    /**
+     * Set the test for this for node
+     *
+     * @param lc lexical context
+     * @param test new test
+     * @return same or new node depending on if test was changed
+     */
+    public abstract LoopNode setTest(final LexicalContext lc, final Node test);
+
+    /**
+     * Set the control flow escapes flag for this node.
+     * TODO  - integrate this with Lowering in a better way
+     *
+     * @param lc lexical context
+     * @param controlFlowEscapes control flow escapes value
+     * @return new loop node if changed otherwise the same
+     */
+    public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
+
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/Node.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java	Thu May 16 11:47:51 2013 +0100
@@ -25,7 +25,9 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.IdentityHashMap;
+import java.util.ArrayList;
+import java.util.List;
+
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Token;
@@ -33,30 +35,17 @@
 
 /**
  * Nodes are used to compose Abstract Syntax Trees.
- *
  */
 public abstract class Node extends Location {
     /** Node symbol. */
     private Symbol symbol;
 
     /** Start of source range. */
-    protected int start;
+    protected final int start;
 
     /** End of source range. */
     protected int finish;
 
-    /** Has this node been resolved - i.e. emitted code already */
-    private boolean isResolved;
-
-    /** Is this node terminal */
-    private boolean isTerminal;
-
-    /** Is this a goto node */
-    private boolean hasGoto;
-
-    /** Is this a discard */
-    private boolean shouldDiscard;
-
     /**
      * Constructor
      *
@@ -72,6 +61,21 @@
     }
 
     /**
+     * Constructor
+     *
+     * @param source  source
+     * @param token   token
+     * @param start   start
+     * @param finish  finish
+     */
+    protected Node(final Source source, final long token, final int start, final int finish) {
+        super(source, token);
+
+        this.start = start;
+        this.finish = finish;
+    }
+
+    /**
      * Copy constructor
      *
      * @param node source node
@@ -79,13 +83,9 @@
     protected Node(final Node node) {
         super(node);
 
-        this.symbol        = node.symbol;
-        this.isResolved    = node.isResolved;
-        this.isTerminal    = node.isTerminal;
-        this.hasGoto       = node.hasGoto;
-        this.shouldDiscard = node.shouldDiscard;
-        this.start         = node.start;
-        this.finish        = node.finish;
+        this.symbol = node.symbol;
+        this.start  = node.start;
+        this.finish = node.finish;
     }
 
     /**
@@ -156,28 +156,6 @@
     }
 
     /**
-     * Test to see if code been generated for this node. Set isResolved if not.
-     *
-     * @return True if node has already been resolved.
-     */
-    public boolean testResolved() {
-        if (isResolved()) {
-            return true;
-        }
-
-        setIsResolved(true);
-
-        return false;
-    }
-
-    /**
-     * Reset the resolved flag.
-     */
-    public void resetResolved() {
-        setIsResolved(false);
-    }
-
-    /**
      * Is this a debug info node like LineNumberNode etc?
      *
      * @return true if this is a debug node
@@ -187,72 +165,13 @@
     }
 
     /**
-     * Helper class used for node cloning
+     * For reference copies - ensure that labels in the copy node are unique
+     * using an appropriate copy constructor
+     * @param lc lexical context
+     * @return new node or same of no labels
      */
-    public static final class CopyState {
-        private final IdentityHashMap<Node, Node> cloneMap = new IdentityHashMap<>();
-
-        /**
-         * Find existing or create new copy of the node.
-         *
-         * @param node Node to copy.
-         *
-         * @return New object.
-         */
-        public Node existingOrCopy(final Node node) {
-            if (node != null) {
-                Node copy = cloneMap.get(node);
-
-                if (copy == null) {
-                    copy = node.copy(this);
-                    cloneMap.put(node, copy);
-                }
-
-                return copy;
-            }
-
-            return node;
-        }
-
-        /**
-         * Find existing or use old copy of the node.
-         *
-         * @param node Node to copy.
-         *
-         * @return new object.
-         */
-        public Node existingOrSame(final Node node) {
-            if (node != null) {
-                Node copy = cloneMap.get(node);
-
-                if (copy == null) {
-                    copy = node;
-                }
-
-                return copy;
-            }
-
-            return node;
-        }
-    }
-
-    /**
-     * Deep copy the node.
-     *
-     * @return Deep copy of the  Node.
-     */
-    public final Node copy() {
-        return copy(new CopyState());
-    }
-
-    /**
-     * Deep copy the node.
-     *
-     * @param cs CopyState passed around to re-use certain nodes.
-     * @return Deep copy of the  Node.
-     */
-    protected Node copy(final CopyState cs) {
-        return cs.existingOrCopy(this);
+    public Node ensureUniqueLabels(final LexicalContext lc) {
+        return this;
     }
 
     /**
@@ -283,35 +202,7 @@
      * @return true if terminal
      */
     public boolean hasTerminalFlags() {
-        return isTerminal || hasGoto;
-    }
-
-    /**
-     * Copy the terminal flags state of a node to another node
-     *
-     * @param other source node
-     */
-    public void copyTerminalFlags(final Node other) {
-        isTerminal = other.isTerminal;
-        hasGoto    = other.hasGoto;
-    }
-
-    /**
-     * Check if the return value of this expression should be discarded
-     * @return true if return value is discarded
-     */
-    public boolean shouldDiscard() {
-        return shouldDiscard;
-    }
-
-    /**
-     * Setter that determines whether this node's return value should be discarded
-     * or not
-     *
-     * @param shouldDiscard true if return value is discarded, false otherwise
-     */
-    public void setDiscard(final boolean shouldDiscard) {
-        this.shouldDiscard = shouldDiscard;
+        return isTerminal() || hasGoto();
     }
 
     /**
@@ -336,29 +227,7 @@
      * @return true if node has goto semantics
      */
     public boolean hasGoto() {
-        return hasGoto;
-    }
-
-    /**
-     * Flag this node as having goto semantics as described in {@link Node#hasGoto()}
-     */
-    public void setHasGoto() {
-        this.hasGoto = true;
-    }
-
-    /**
-     * Check whether this node is resolved, i.e. code has been generated for it
-     * @return true if node is resolved
-     */
-    public boolean isResolved() {
-        return isResolved;
-    }
-
-    /**
-     * Flag this node as resolved or not, i.e. code has been generated for it
-     */
-    private void setIsResolved(boolean isResolved) {
-        this.isResolved = isResolved;
+        return false;
     }
 
     /**
@@ -370,14 +239,6 @@
     }
 
     /**
-     * Set start position for node
-     * @param start start position
-     */
-    public void setStart(final int start) {
-        this.start = start;
-    }
-
-    /**
      * Return the Symbol the compiler has assigned to this Node. The symbol
      * is the place where it's expression value is stored after evaluation
      *
@@ -404,17 +265,29 @@
      * @return true if this node is terminal
      */
     public boolean isTerminal() {
-        return isTerminal;
+        return false;
     }
 
-    /**
-     * Set this to be a terminal node, i.e. it terminates control flow as described
-     * in {@link Node#isTerminal()}
-     *
-     * @param isTerminal true if this is a terminal node, false otherwise
-     */
-    public void setIsTerminal(final boolean isTerminal) {
-        this.isTerminal = isTerminal;
+    //on change, we have to replace the entire list, that's we can't simple do ListIterator.set
+    static <T extends Node> List<T> accept(final NodeVisitor visitor, final Class<T> clazz, final List<T> list) {
+        boolean changed = false;
+        final List<T> newList = new ArrayList<>();
+
+        for (final Node node : list) {
+            final T newNode = clazz.cast(node.accept(visitor));
+            if (newNode != node) {
+                changed = true;
+            }
+            newList.add(newNode);
+        }
+
+        return changed ? newList : list;
     }
 
+    static <T extends LexicalContextNode> T replaceInLexicalContext(final LexicalContext lc, final T oldNode, final T newNode) {
+        if (lc != null) {
+            lc.replace(oldNode, newNode);
+        }
+        return newNode;
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,16 +25,18 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an object literal.
  */
-public class ObjectNode extends Node {
+@Immutable
+public final class ObjectNode extends Node {
 
     /** Literal elements. */
     private final List<Node> elements;
@@ -49,35 +51,18 @@
      */
     public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) {
         super(source, token, finish);
-
         this.elements = elements;
     }
 
-    private ObjectNode(final ObjectNode objectNode, final CopyState cs) {
+    private ObjectNode(final ObjectNode objectNode, final List<Node> elements) {
         super(objectNode);
-
-        final List<Node> newElements = new ArrayList<>();
-
-        for (final Node element : objectNode.elements) {
-            newElements.add(cs.existingOrCopy(element));
-        }
-
-        this.elements = newElements;
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new ObjectNode(this, cs);
+        this.elements = elements;
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterObjectNode(this) != null) {
-            for (int i = 0, count = elements.size(); i < count; i++) {
-                elements.set(i, elements.get(i).accept(visitor));
-            }
-
-            return visitor.leaveObjectNode(this);
+        if (visitor.enterObjectNode(this)) {
+            return visitor.leaveObjectNode(setElements(Node.accept(visitor, Node.class, elements)));
         }
 
         return this;
@@ -112,4 +97,11 @@
     public List<Node> getElements() {
         return Collections.unmodifiableList(elements);
     }
+
+    private ObjectNode setElements(final List<Node> elements) {
+        if (this.elements == elements) {
+            return this;
+        }
+        return new ObjectNode(this, elements);
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,28 +25,27 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.ir.annotations.Reference;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of an object literal property.
  */
-public class PropertyNode extends Node {
+@Immutable
+public final class PropertyNode extends Node {
 
     /** Property key. */
-    private PropertyKey key;
+    private final PropertyKey key;
 
     /** Property value. */
-    private Node value;
+    private final Node value;
 
     /** Property getter. */
-    @Reference
-    private Node getter;
+    private final FunctionNode getter;
 
     /** Property getter. */
-    @Reference
-    private Node setter;
+    private final FunctionNode setter;
 
     /**
      * Constructor
@@ -56,26 +55,23 @@
      * @param finish  finish
      * @param key     the key of this property
      * @param value   the value of this property
+     * @param getter  getter function body
+     * @param setter  setter function body
      */
-    public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value) {
+    public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
         super(source, token, finish);
-
         this.key    = key;
         this.value  = value;
+        this.getter = getter;
+        this.setter = setter;
     }
 
-    private PropertyNode(final PropertyNode propertyNode, final CopyState cs) {
+    private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) {
         super(propertyNode);
-
-        this.key    = (PropertyKey)cs.existingOrCopy((Node)propertyNode.key);
-        this.value  = cs.existingOrCopy(propertyNode.value);
-        this.getter = cs.existingOrSame(propertyNode.getter);
-        this.setter = cs.existingOrSame(propertyNode.setter);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new PropertyNode(this, cs);
+        this.key    = key;
+        this.value  = value;
+        this.getter = getter;
+        this.setter = setter;
     }
 
     /**
@@ -88,22 +84,12 @@
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterPropertyNode(this) != null) {
-            key = (PropertyKey)((Node)key).accept(visitor);
-
-            if (value != null) {
-                value = value.accept(visitor);
-            }
-
-            if (getter != null) {
-                getter = getter.accept(visitor);
-            }
-
-            if (setter != null) {
-                setter = setter.accept(visitor);
-            }
-
-            return visitor.leavePropertyNode(this);
+        if (visitor.enterPropertyNode(this)) {
+            return visitor.leavePropertyNode(
+                setKey((PropertyKey)((Node)key).accept(visitor)).
+                setValue(value == null ? null : value.accept(visitor)).
+                setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
+                setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
         }
 
         return this;
@@ -136,16 +122,20 @@
      * Get the getter for this property
      * @return getter or null if none exists
      */
-    public Node getGetter() {
+    public FunctionNode getGetter() {
         return getter;
     }
 
     /**
      * Set the getter of this property, null if none
      * @param getter getter
+     * @return same node or new node if state changed
      */
-    public void setGetter(final Node getter) {
-        this.getter = getter;
+    public PropertyNode setGetter(final FunctionNode getter) {
+        if (this.getter == getter) {
+            return this;
+        }
+        return new PropertyNode(this, key, value, getter, setter);
     }
 
     /**
@@ -156,20 +146,31 @@
         return (Node)key;
     }
 
+    private PropertyNode setKey(final PropertyKey key) {
+        if (this.key == key) {
+            return this;
+        }
+        return new PropertyNode(this, key, value, getter, setter);
+    }
+
     /**
      * Get the setter for this property
      * @return setter or null if none exists
      */
-    public Node getSetter() {
+    public FunctionNode getSetter() {
         return setter;
     }
 
     /**
      * Set the setter for this property, null if none
      * @param setter setter
+     * @return same node or new node if state changed
      */
-    public void setSetter(final Node setter) {
-        this.setter = setter;
+    public PropertyNode setSetter(final FunctionNode setter) {
+        if (this.setter == setter) {
+            return this;
+        }
+        return new PropertyNode(this, key, value, getter, setter);
     }
 
     /**
@@ -183,8 +184,12 @@
     /**
      * Set the value of this property
      * @param value new value
+     * @return same node or new node if state changed
      */
-    public void setValue(final Node value) {
-        this.value = value;
-    }
+    public PropertyNode setValue(final Node value) {
+        if (this.value == value) {
+            return this;
+        }
+        return new PropertyNode(this, key, value, getter, setter);
+   }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java	Thu May 16 11:47:51 2013 +0100
@@ -27,22 +27,17 @@
 
 import static jdk.nashorn.internal.parser.TokenType.RETURN;
 import static jdk.nashorn.internal.parser.TokenType.YIELD;
-
-import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for RETURN or YIELD statements.
- *
  */
+@Immutable
 public class ReturnNode extends Node {
     /** Optional expression. */
-    private Node expression;
-
-    /** Try chain. */
-    @Ignore
-    private final TryNode tryChain;
+    private final Node expression;
 
     /**
      * Constructor
@@ -51,27 +46,20 @@
      * @param token      token
      * @param finish     finish
      * @param expression expression to return
-     * @param tryChain   surrounding try chain.
      */
-    public ReturnNode(final Source source, final long token, final int finish, final Node expression, final TryNode tryChain) {
+    public ReturnNode(final Source source, final long token, final int finish, final Node expression) {
         super(source, token, finish);
-
         this.expression = expression;
-        this.tryChain   = tryChain;
-
-        setIsTerminal(true);
     }
 
-    private ReturnNode(final ReturnNode returnNode, final CopyState cs) {
+    private ReturnNode(final ReturnNode returnNode, final Node expression) {
         super(returnNode);
-
-        this.expression = cs.existingOrCopy(returnNode.expression);
-        this.tryChain   = (TryNode)cs.existingOrSame(returnNode.tryChain);
+        this.expression = expression;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new ReturnNode(this, cs);
+    public boolean isTerminal() {
+        return true;
     }
 
     /**
@@ -100,11 +88,10 @@
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterReturnNode(this) != null) {
+        if (visitor.enterReturnNode(this)) {
             if (expression != null) {
-                expression = expression.accept(visitor);
+                return visitor.leaveReturnNode(setExpression(expression.accept(visitor)));
             }
-
             return visitor.leaveReturnNode(this);
         }
 
@@ -121,25 +108,6 @@
         }
     }
 
-    @Override
-    public boolean equals(final Object other) {
-        if (other instanceof ReturnNode) {
-            final ReturnNode otherReturn = (ReturnNode)other;
-            if (hasExpression() != otherReturn.hasExpression()) {
-                return false;
-            } else if (hasExpression()) {
-                return otherReturn.getExpression().equals(getExpression());
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return 0x4711_17 ^ (expression == null ? 0 : expression.hashCode());
-    }
-
     /**
      * Get the expression this node returns
      * @return return expression, or null if void return
@@ -151,16 +119,13 @@
     /**
      * Reset the expression this node returns
      * @param expression new expression, or null if void return
+     * @return new or same return node
      */
-    public void setExpression(final Node expression) {
-        this.expression = expression;
+    public ReturnNode setExpression(final Node expression) {
+        if (this.expression == expression) {
+            return this;
+        }
+        return new ReturnNode(this, expression);
     }
 
-    /**
-     * Get the surrounding try chain for this return node
-     * @return try chain
-     */
-    public TryNode getTryChain() {
-        return tryChain;
-    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java	Thu May 16 11:47:51 2013 +0100
@@ -30,14 +30,15 @@
 import java.util.Collections;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for a runtime call.
- *
  */
+@Immutable
 public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
 
     /**
@@ -271,10 +272,10 @@
     private final List<Node> args;
 
     /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */
-    private Type callSiteType;
+    private final Type callSiteType;
 
     /** is final - i.e. may not be removed again, lower in the code pipeline */
-    private boolean isFinal;
+    private final boolean isFinal;
 
     /**
      * Constructor
@@ -290,6 +291,17 @@
 
         this.request      = request;
         this.args         = args;
+        this.callSiteType = null;
+        this.isFinal      = false;
+    }
+
+    private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Node> args) {
+        super(runtimeNode);
+
+        this.request      = request;
+        this.args         = args;
+        this.callSiteType = callSiteType;
+        this.isFinal      = isFinal;
     }
 
     /**
@@ -326,8 +338,10 @@
     public RuntimeNode(final Node parent, final Request request, final List<Node> args) {
         super(parent);
 
-        this.request = request;
-        this.args    = args;
+        this.request      = request;
+        this.args         = args;
+        this.callSiteType = null;
+        this.isFinal      = false;
     }
 
     /**
@@ -350,20 +364,6 @@
         this(parent, request, parent.lhs(), parent.rhs());
     }
 
-    private RuntimeNode(final RuntimeNode runtimeNode, final CopyState cs) {
-        super(runtimeNode);
-
-        final List<Node> newArgs = new ArrayList<>();
-
-        for (final Node arg : runtimeNode.args) {
-            newArgs.add(cs.existingOrCopy(arg));
-        }
-
-        this.request      = runtimeNode.request;
-        this.args         = newArgs;
-        this.callSiteType = runtimeNode.callSiteType;
-    }
-
     /**
      * Is this node final - i.e. it can never be replaced with other nodes again
      * @return true if final
@@ -374,14 +374,14 @@
 
     /**
      * Flag this node as final - i.e it may never be replaced with other nodes again
+     * @param isFinal is the node final, i.e. can not be removed and replaced by a less generic one later in codegen
+     * @return same runtime node if already final, otherwise a new one
      */
-    public void setIsFinal() {
-        this.isFinal = true;
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new RuntimeNode(this, cs);
+    public RuntimeNode setIsFinal(final boolean isFinal) {
+        if (this.isFinal == isFinal) {
+            return this;
+        }
+        return new RuntimeNode(this, request, callSiteType, isFinal, args);
     }
 
     /**
@@ -394,8 +394,10 @@
 
     @Override
     public RuntimeNode setType(final Type type) {
-        this.callSiteType = type;
-        return this;
+        if (this.callSiteType == type) {
+            return this;
+        }
+        return new RuntimeNode(this, request, type, isFinal, args);
     }
 
     @Override
@@ -409,12 +411,12 @@
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterRuntimeNode(this) != null) {
-            for (int i = 0, count = args.size(); i < count; i++) {
-                args.set(i, args.get(i).accept(visitor));
+        if (visitor.enterRuntimeNode(this)) {
+            final List<Node> newArgs = new ArrayList<>();
+            for (final Node arg : args) {
+                newArgs.add(arg.accept(visitor));
             }
-
-            return visitor.leaveRuntimeNode(this);
+            return visitor.leaveRuntimeNode(setArgs(newArgs));
         }
 
         return this;
@@ -449,6 +451,13 @@
         return Collections.unmodifiableList(args);
     }
 
+    private RuntimeNode setArgs(final List<Node> args) {
+        if (this.args == args) {
+            return this;
+        }
+        return new RuntimeNode(this, request, callSiteType, isFinal, args);
+    }
+
     /**
      * Get the request that this runtime node implements
      * @return the request
--- a/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,99 +25,65 @@
 
 package jdk.nashorn.internal.ir;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 import jdk.nashorn.internal.codegen.CompileUnit;
-import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.codegen.MethodEmitter;
-import jdk.nashorn.internal.ir.annotations.Ignore;
-import jdk.nashorn.internal.ir.annotations.Reference;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
-
 /**
  * Node indicating code is split across classes.
  */
-public class SplitNode extends Node {
+@Immutable
+public class SplitNode extends LexicalContextNode {
     /** Split node method name. */
     private final String name;
 
     /** Compilation unit. */
-    private CompileUnit compileUnit;
-
-    /** Method emitter for current method. */
-    private MethodEmitter method;
-
-    /** Method emitter for caller method. */
-    private MethodEmitter caller;
-
-    /** Containing function. */
-    @Reference
-    private final FunctionNode functionNode;
-
-    /** A list of target labels in parent methods this split node may encounter. */
-    @Ignore
-    private final List<Label> externalTargets;
-
-    /** True if this split node or any of its children contain a return statement. */
-    private boolean hasReturn;
+    private final CompileUnit compileUnit;
 
     /** Body of split code. */
-    @Ignore
-    private Node body;
+    private final Node body;
 
     /**
      * Constructor
      *
-     * @param name          name of split node
-     * @param functionNode  function node to split in
-     * @param body          body of split code
+     * @param name        name of split node
+     * @param body        body of split code
+     * @param compileUnit compile unit to use for the body
      */
-    public SplitNode(final String name, final FunctionNode functionNode, final Node body) {
+    public SplitNode(final String name, final Node body, final CompileUnit compileUnit) {
         super(body.getSource(), body.getToken(), body.getFinish());
-
-        this.name         = name;
-        this.functionNode = functionNode;
-        this.body         = body;
-        this.externalTargets = new ArrayList<>();
+        this.name        = name;
+        this.body        = body;
+        this.compileUnit = compileUnit;
     }
 
-    private SplitNode(final SplitNode splitNode, final CopyState cs) {
+    private SplitNode(final SplitNode splitNode, final Node body) {
         super(splitNode);
+        this.name        = splitNode.name;
+        this.body        = body;
+        this.compileUnit = splitNode.compileUnit;
+    }
 
-        this.name         = splitNode.name;
-        this.functionNode = (FunctionNode)cs.existingOrSame(splitNode.functionNode);
-        this.body         = cs.existingOrCopy(splitNode.body);
-        this.externalTargets = new ArrayList<>();
+    /**
+     * Get the body for this split node - i.e. the actual code it encloses
+     * @return body for split node
+     */
+    public Node getBody() {
+        return body;
+    }
+
+    private SplitNode setBody(final LexicalContext lc, final Node body) {
+        if (this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body));
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new SplitNode(this, cs);
-    }
-
-    @Override
-    public Node accept(final NodeVisitor visitor) {
-        final CompileUnit   saveCompileUnit = visitor.getCurrentCompileUnit();
-        final MethodEmitter saveMethod      = visitor.getCurrentMethodEmitter();
-
-        setCaller(saveMethod);
-
-        visitor.setCurrentCompileUnit(getCompileUnit());
-        visitor.setCurrentMethodEmitter(getMethodEmitter());
-
-        try {
-            if (visitor.enterSplitNode(this) != null) {
-                body = body.accept(visitor);
-
-                return visitor.leaveSplitNode(this);
-            }
-        } finally {
-            visitor.setCurrentCompileUnit(saveCompileUnit);
-            visitor.setCurrentMethodEmitter(saveMethod);
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterSplitNode(this)) {
+            return visitor.leaveSplitNode(setBody(lc, body.accept(visitor)));
         }
-
         return this;
     }
 
@@ -130,22 +96,6 @@
     }
 
     /**
-     * Get the method emitter of the caller for this split node
-     * @return caller method emitter
-     */
-    public MethodEmitter getCaller() {
-        return caller;
-    }
-
-    /**
-     * Set the caller method emitter for this split node
-     * @param caller method emitter
-     */
-    public void setCaller(final MethodEmitter caller) {
-        this.caller = caller;
-    }
-
-    /**
      * Get the name for this split node
      * @return name
      */
@@ -161,67 +111,4 @@
         return compileUnit;
     }
 
-    /**
-     * Set the compile unit for this split node
-     * @param compileUnit compile unit
-     */
-    public void setCompileUnit(final CompileUnit compileUnit) {
-        this.compileUnit = compileUnit;
-    }
-
-    /**
-     * Get the method emitter for this split node
-     * @return method emitter
-     */
-    public MethodEmitter getMethodEmitter() {
-        return method;
-    }
-
-    /**
-     * Set the method emitter for this split node
-     * @param method method emitter
-     */
-    public void setMethodEmitter(final MethodEmitter method) {
-        this.method = method;
-    }
-
-    /**
-     * Get the function node this SplitNode splits
-     * @return function node reference
-     */
-    public FunctionNode getFunctionNode() {
-        return functionNode;
-    }
-
-    /**
-     * Get the external targets for this SplitNode
-     * @return list of external targets
-     */
-    public List<Label> getExternalTargets() {
-        return Collections.unmodifiableList(externalTargets);
-    }
-
-    /**
-     * Add an external target for this SplitNode
-     * @param targetLabel target label
-     */
-    public void addExternalTarget(final Label targetLabel) {
-        externalTargets.add(targetLabel);
-    }
-
-    /**
-     * Check whether this SplitNode returns a value
-     * @return true if return
-     */
-    public boolean hasReturn() {
-        return hasReturn;
-    }
-
-    /**
-     * Set whether this SplitNode returns a value or not
-     * @param hasReturn true if return exists, false otherwise
-     */
-    public void setHasReturn(final boolean hasReturn) {
-        this.hasReturn = hasReturn;
-    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java	Thu May 16 11:47:51 2013 +0100
@@ -28,73 +28,84 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+
 import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a SWITCH statement.
  */
-public class SwitchNode extends BreakableNode {
+@Immutable
+public final class SwitchNode extends BreakableNode {
     /** Switch expression. */
-    private Node expression;
+    private final Node expression;
+
+    /** Switch cases. */
+    private final List<CaseNode> cases;
+
+    /** Switch default index. */
+    private final int defaultCaseIndex;
 
     /** Tag symbol. */
     private Symbol tag;
 
-    /** Switch cases. */
-    private List<CaseNode> cases;
-
-    /** Switch default. */
-    @Ignore //points to one of the members in the list above, don't traverse twice
-    private CaseNode defaultCase;
-
     /**
      * Constructor
      *
-     * @param source  the source
-     * @param token   token
-     * @param finish  finish
+     * @param source      the source
+     * @param token       token
+     * @param finish      finish
+     * @param expression  switch expression
+     * @param cases       cases
+     * @param defaultCase the default case node - null if none, otherwise has to be present in cases list
      */
-    public SwitchNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
-        this.breakLabel  = new Label("switch_break");
+    public SwitchNode(final Source source, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) {
+        super(source, token, finish, new Label("switch_break"));
+        this.expression       = expression;
+        this.cases            = cases;
+        this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
     }
 
-    private SwitchNode(final SwitchNode switchNode, final CopyState cs) {
+    private SwitchNode(final SwitchNode switchNode, final Node expression, final List<CaseNode> cases, final int defaultCase) {
         super(switchNode);
-
-        final List<CaseNode> newCases = new ArrayList<>();
-
-        for (final CaseNode caseNode : switchNode.getCases()) {
-           newCases.add((CaseNode)cs.existingOrCopy(caseNode));
-        }
-
-        this.expression  = cs.existingOrCopy(switchNode.getExpression());
-        this.tag         = switchNode.getTag();
-        this.cases       = newCases;
-        this.defaultCase = (CaseNode)cs.existingOrCopy(switchNode.getDefaultCase());
-        this.breakLabel  = new Label(switchNode.getBreakLabel());
+        this.expression       = expression;
+        this.cases            = cases;
+        this.defaultCaseIndex = defaultCase;
+        this.tag              = switchNode.getTag(); //TODO are symbols inhereted as references?
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new SwitchNode(this, cs);
+    public Node ensureUniqueLabels(final LexicalContext lc) {
+        final List<CaseNode> newCases = new ArrayList<>();
+        for (final CaseNode caseNode : cases) {
+            newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody()));
+        }
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex));
     }
 
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterSwitchNode(this) != null) {
-            expression = expression.accept(visitor);
+    public boolean isTerminal() {
+        //there must be a default case, and that including all other cases must terminate
+        if (!cases.isEmpty() && defaultCaseIndex != -1) {
+            for (final CaseNode caseNode : cases) {
+                if (!caseNode.isTerminal()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
 
-            for (int i = 0, count = cases.size(); i < count; i++) {
-                cases.set(i, (CaseNode)cases.get(i).accept(visitor));
-            }
+    }
 
-            //the default case is in the cases list and should not be explicitly traversed!
-
-            return visitor.leaveSwitchNode(this);
+    @Override
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterSwitchNode(this)) {
+            return visitor.leaveSwitchNode(
+                setExpression(visitor.getLexicalContext(), expression.accept(visitor)).
+                setCases(visitor.getLexicalContext(), Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex));
         }
 
         return this;
@@ -108,6 +119,14 @@
     }
 
     /**
+     * Return the case node that is default case
+     * @return default case or null if none
+     */
+    public CaseNode getDefaultCase() {
+        return defaultCaseIndex == -1 ? null : cases.get(defaultCaseIndex);
+    }
+
+    /**
      * Get the cases in this switch
      * @return a list of case nodes
      */
@@ -116,27 +135,33 @@
     }
 
     /**
-     * Set or reset the list of cases in this switch
-     * @param cases a list of cases, case nodes
+     * Replace case nodes with new list. the cases have to be the same
+     * and the default case index the same. This is typically used
+     * by NodeVisitors who perform operations on every case node
+     * @param lc    lexical context
+     * @param cases list of cases
+     * @return new switcy node or same if no state was changed
      */
-    public void setCases(final List<CaseNode> cases) {
-        this.cases = cases;
+    public SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases) {
+        return setCases(lc, cases, defaultCaseIndex);
+    }
+
+    private SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases, final int defaultCaseIndex) {
+        if (this.cases == cases) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex));
     }
 
     /**
-     * Get the default case for this switch
-     * @return default case node
+     * Set or reset the list of cases in this switch
+     * @param lc lexical context
+     * @param cases a list of cases, case nodes
+     * @param defaultCase a case in the list that is the default - must be in the list or class will assert
+     * @return new switch node or same if no state was changed
      */
-    public CaseNode getDefaultCase() {
-        return defaultCase;
-    }
-
-    /**
-     * Set the default case for this switch
-     * @param defaultCase default case node
-     */
-    public void setDefaultCase(final CaseNode defaultCase) {
-        this.defaultCase = defaultCase;
+    public SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases, final CaseNode defaultCase) {
+        return setCases(lc, cases, defaultCase == null ? -1 : cases.indexOf(defaultCase));
     }
 
     /**
@@ -149,10 +174,15 @@
 
     /**
      * Set or reset the expression to switch on
+     * @param lc lexical context
      * @param expression switch expression
+     * @return new switch node or same if no state was changed
      */
-    public void setExpression(final Node expression) {
-        this.expression = expression;
+    public SwitchNode setExpression(final LexicalContext lc, final Node expression) {
+        if (this.expression == expression) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex));
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java	Thu May 16 11:47:51 2013 +0100
@@ -29,8 +29,10 @@
 import java.util.HashSet;
 import java.util.Set;
 import java.util.StringTokenizer;
+
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.options.Options;
 
 /**
@@ -63,6 +65,8 @@
     public static final int IS_LET           = 1 << 8;
     /** Is this an internal symbol, never represented explicitly in source code */
     public static final int IS_INTERNAL      = 1 << 9;
+    /** Is this a function self-reference symbol */
+    public static final int IS_FUNCTION_SELF = 1 << 10;
 
     /** Null or name identifying symbol. */
     private final String name;
@@ -70,12 +74,6 @@
     /** Symbol flags. */
     private int flags;
 
-    /** Defining node. */
-    private Node node;
-
-    /** Definition block. */
-    private final Block block;
-
     /** Type of symbol. */
     private Type type;
 
@@ -121,16 +119,12 @@
      *
      * @param name  name of symbol
      * @param flags symbol flags
-     * @param node  node this symbol is in
-     * @param block block this symbol is in
      * @param type  type of this symbol
      * @param slot  bytecode slot for this symbol
      */
-    protected Symbol(final String name, final int flags, final Node node, final Block block, final Type type, final int slot) {
+    protected Symbol(final String name, final int flags, final Type type, final int slot) {
         this.name       = name;
         this.flags      = flags;
-        this.node       = node;
-        this.block      = block;
         this.type       = type;
         this.slot       = slot;
         this.fieldIndex = -1;
@@ -142,11 +136,9 @@
      *
      * @param name  name of symbol
      * @param flags symbol flags
-     * @param node  node this symbol is in
-     * @param block block this symbol is in
      */
-    public Symbol(final String name, final int flags, final Node node, final Block block) {
-        this(name, flags, node, block, Type.UNKNOWN, -1);
+    public Symbol(final String name, final int flags) {
+        this(name, flags, Type.UNKNOWN, -1);
     }
 
     /**
@@ -157,7 +149,7 @@
      * @param type  type of this symbol
      */
     public Symbol(final String name, final int flags, final Type type) {
-        this(name, flags, null, null, type, -1);
+        this(name, flags, type, -1);
     }
 
     private static String align(final String string, final int max) {
@@ -269,20 +261,6 @@
         return type.isCategory2() ? 2 : 1;
     }
 
-    @Override
-    public boolean equals(final Object other) {
-        if (!(other instanceof Symbol)) {
-            return false;
-        }
-        final Symbol symbol = (Symbol) other;
-        return name.equals(symbol.name) && block.equals(symbol.block);
-    }
-
-    @Override
-    public int hashCode() {
-        return name.hashCode() ^ block.hashCode();
-    }
-
     private static String type(final String desc) {
         switch (desc.charAt(desc.length() - 1)) {
         case ';':
@@ -371,14 +349,14 @@
     /**
      * Flag this symbol as scope as described in {@link Symbol#isScope()}
      */
-    public void setIsScope() {
+    /**
+     * Flag this symbol as scope as described in {@link Symbol#isScope()}
+     */
+     public void setIsScope() {
         if (!isScope()) {
             trace("SET IS SCOPE");
         }
         flags |= IS_SCOPE;
-        if(!isGlobal()) {
-            getBlock().setNeedsScope();
-        }
     }
 
     /**
@@ -478,11 +456,11 @@
     }
 
     /**
-     * Get the block in which the symbol is defined
-     * @return a block
+     * Flag this symbol as a function's self-referencing symbol.
+     * @return true if this symbol as a function's self-referencing symbol.
      */
-    public Block getBlock() {
-        return block;
+    public boolean isFunctionSelf() {
+        return (flags & IS_FUNCTION_SELF) == IS_FUNCTION_SELF;
     }
 
     /**
@@ -492,7 +470,7 @@
      * @return field index
      */
     public int getFieldIndex() {
-        assert fieldIndex != -1 : "fieldIndex must be initialized";
+        assert fieldIndex != -1 : "fieldIndex must be initialized " + fieldIndex;
         return fieldIndex;
     }
 
@@ -503,7 +481,6 @@
      * @param fieldIndex field index - a positive integer
      */
     public void setFieldIndex(final int fieldIndex) {
-        assert this.fieldIndex == -1 : "fieldIndex must be initialized only once";
         this.fieldIndex = fieldIndex;
     }
 
@@ -524,22 +501,6 @@
     }
 
     /**
-     * Get the node this symbol stores the result for
-     * @return node
-     */
-    public Node getNode() {
-        return node;
-    }
-
-    /**
-     * Set the node this symbol stores the result for
-     * @param node node
-     */
-    public void setNode(final Node node) {
-        this.node = node;
-    }
-
-    /**
      * Get the name of this symbol
      * @return symbol name
      */
@@ -616,18 +577,25 @@
     }
 
     /**
-     * Check if this symbol is in the global scope, i.e. it is on the outermost level
-     * in the script
-     * @return true if this this is a global scope symbol
+     * From a lexical context, set this symbol as needing scope, which
+     * will set flags for the defining block that will be written when
+     * block is popped from the lexical context stack, used by codegen
+     * when flags need to be tagged, but block is in the
+     * middle of evaluation and cannot be modified.
+     *
+     * @param lc     lexical context
+     * @param symbol symbol
      */
-    public boolean isTopLevel() {
-        return block instanceof FunctionNode && ((FunctionNode) block).isProgram();
+    public static void setSymbolIsScope(final LexicalContext lc, final Symbol symbol) {
+        symbol.setIsScope();
+        if (!symbol.isGlobal()) {
+            lc.setFlag(lc.getDefiningBlock(symbol), Block.NEEDS_SCOPE);
+        }
     }
 
-
     private void trace(final String desc) {
         if (TRACE_SYMBOLS != null && (TRACE_SYMBOLS.isEmpty() || TRACE_SYMBOLS.contains(name))) {
-            Context.err("SYMBOL: '" + name + "' " + desc);
+            Context.err(Debug.id(this) + " SYMBOL: '" + name + "' " + desc);
             if (TRACE_SYMBOLS_STACKTRACE != null && (TRACE_SYMBOLS_STACKTRACE.isEmpty() || TRACE_SYMBOLS_STACKTRACE.contains(name))) {
                 new Throwable().printStackTrace(Context.getCurrentErr());
             }
--- a/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,15 +25,21 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * TernaryNode nodes represent three operand operations (?:).
  */
-public class TernaryNode extends BinaryNode {
+@Immutable
+public final class TernaryNode extends Node {
+    private final Node lhs;
+
+    private final Node rhs;
+
     /** Third argument. */
-    private Node third;
+    private final Node third;
 
     /**
      * Constructor
@@ -45,43 +51,26 @@
      * @param third  third node
      */
     public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) {
-        super(source, token, lhs, rhs);
-
-        this.finish = third.getFinish();
+        super(source, token, third.getFinish());
+        this.lhs = lhs;
+        this.rhs = rhs;
         this.third = third;
     }
 
-    private TernaryNode(final TernaryNode ternaryNode, final CopyState cs) {
-        super(ternaryNode, cs);
-
-        this.third = cs.existingOrCopy(ternaryNode.third);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new TernaryNode(this, cs);
-    }
-
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        return third.equals(((TernaryNode)other).third());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ third().hashCode();
+    private TernaryNode(final TernaryNode ternaryNode, final Node lhs, final Node rhs, final Node third) {
+        super(ternaryNode);
+        this.lhs = lhs;
+        this.rhs = rhs;
+        this.third = third;
     }
 
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterTernaryNode(this) != null) {
+        if (visitor.enterTernaryNode(this)) {
             final Node newLhs = lhs().accept(visitor);
             final Node newRhs = rhs().accept(visitor);
             final Node newThird = third.accept(visitor);
-            return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs));
+            return visitor.leaveTernaryNode(setThird(newThird).setLHS(newLhs).setRHS(newRhs));
         }
 
         return this;
@@ -123,6 +112,22 @@
     }
 
     /**
+     * Get the lhs node for this ternary expression, i.e. "x" in x ? y : z
+     * @return a node
+     */
+    public Node lhs() {
+        return lhs;
+    }
+
+    /**
+     * Get the rhs node for this ternary expression, i.e. "y" in x ? y : z
+     * @return a node
+     */
+    public Node rhs() {
+        return rhs;
+    }
+
+    /**
      * Get the "third" node for this ternary expression, i.e. "z" in x ? y : z
      * @return a node
      */
@@ -131,14 +136,38 @@
     }
 
     /**
+     * Set the left hand side expression for this node
+     * @param lhs new left hand side expression
+     * @return a node equivalent to this one except for the requested change.
+     */
+    public TernaryNode setLHS(final Node lhs) {
+        if (this.lhs == lhs) {
+            return this;
+        }
+        return new TernaryNode(this, lhs, rhs, third);
+    }
+
+    /**
+     * Set the right hand side expression for this node
+     * @param rhs new left hand side expression
+     * @return a node equivalent to this one except for the requested change.
+     */
+    public TernaryNode setRHS(final Node rhs) {
+        if (this.rhs == rhs) {
+            return this;
+        }
+        return new TernaryNode(this, lhs, rhs, third);
+    }
+
+    /**
      * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
      * @param third a node
      * @return a node equivalent to this one except for the requested change.
      */
     public TernaryNode setThird(final Node third) {
-        if(this.third == third) return this;
-        final TernaryNode n = (TernaryNode)clone();
-        n.third = third;
-        return n;
+        if (this.third == third) {
+            return this;
+        }
+        return new TernaryNode(this, lhs, rhs, third);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,20 +25,17 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for THROW statements.
  */
-public class ThrowNode extends Node {
+@Immutable
+public final class ThrowNode extends Node {
     /** Exception expression. */
-    private Node expression;
-
-    /** Try chain. */
-    @Ignore
-    private final TryNode tryChain;
+    private final Node expression;
 
     /**
      * Constructor
@@ -47,26 +44,21 @@
      * @param token      token
      * @param finish     finish
      * @param expression expression to throw
-     * @param tryChain   surrounding try chain
      */
-    public ThrowNode(final Source source, final long token, final int finish, final Node expression, final TryNode tryChain) {
+    public ThrowNode(final Source source, final long token, final int finish, final Node expression) {
         super(source, token, finish);
 
         this.expression = expression;
-        this.tryChain = tryChain;
-        setIsTerminal(true);
     }
 
-    private ThrowNode(final ThrowNode throwNode, final CopyState cs) {
-        super(throwNode);
-
-        this.expression = cs.existingOrCopy(throwNode.expression);
-        this.tryChain = (TryNode)cs.existingOrSame(throwNode.tryChain);
+    private ThrowNode(final Node node, final Node expression) {
+        super(node);
+        this.expression = expression;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new ThrowNode(this, cs);
+    public boolean isTerminal() {
+        return true;
     }
 
     /**
@@ -75,9 +67,8 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterThrowNode(this) != null) {
-            setExpression(expression.accept(visitor));
-            return visitor.leaveThrowNode(this);
+        if (visitor.enterThrowNode(this)) {
+            return visitor.leaveThrowNode(setExpression(expression.accept(visitor)));
         }
 
         return this;
@@ -103,16 +94,13 @@
     /**
      * Reset the expression being thrown by this node
      * @param expression new expression
+     * @return new or same thrownode
      */
-    public void setExpression(final Node expression) {
-        this.expression = expression;
+    public ThrowNode setExpression(final Node expression) {
+        if (this.expression == expression) {
+            return this;
+        }
+        return new ThrowNode(this, expression);
     }
 
-    /**
-     * Get surrounding tryChain for this node
-     * @return try chain
-     */
-    public TryNode getTryChain() {
-        return tryChain;
-    }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java	Thu May 16 11:47:51 2013 +0100
@@ -28,30 +28,28 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+
 import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.ir.annotations.Ignore;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation of a TRY statement.
  */
-public class TryNode extends Node {
-    /** Try chain. */
-    @Ignore //don't print, will be apparent from the AST
-    private TryNode next;
-
+@Immutable
+public final class TryNode extends Node {
     /** Try statements. */
-    private Block body;
+    private final Block body;
 
     /** List of catch clauses. */
-    private List<Block> catchBlocks;
+    private final List<Block> catchBlocks;
 
     /** Finally clause. */
-    private Block finallyBody;
+    private final Block finallyBody;
 
     /** Exit label. */
-    private Label exit;
+    private final Label exit;
 
     /** Exception symbol. */
     private Symbol exception;
@@ -62,37 +60,46 @@
     /**
      * Constructor
      *
-     * @param source  the source
-     * @param token   token
-     * @param finish  finish
-     * @param next    next try node in chain
+     * @param source      the source
+     * @param token       token
+     * @param finish      finish
+     * @param body        try node body
+     * @param catchBlocks list of catch blocks in order
+     * @param finallyBody body of finally block or null if none
      */
-    public TryNode(final Source source, final long token, final int finish, final TryNode next) {
+    public TryNode(final Source source, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
         super(source, token, finish);
-
-        this.next = next;
+        this.body = body;
+        this.catchBlocks = catchBlocks;
+        this.finallyBody = finallyBody;
         this.exit = new Label("exit");
     }
 
-    private TryNode(final TryNode tryNode, final CopyState cs) {
+    private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) {
         super(tryNode);
-
-        final List<Block> newCatchBlocks = new ArrayList<>();
-
-        for (final Block block : tryNode.catchBlocks) {
-            newCatchBlocks.add((Block)cs.existingOrCopy(block));
-        }
-
-        this.next        = (TryNode)cs.existingOrSame(tryNode.getNext());
-        this.body        = (Block)cs.existingOrCopy(tryNode.getBody());
-        this.catchBlocks = newCatchBlocks;
-        this.finallyBody = (Block)cs.existingOrCopy(tryNode.getFinallyBody());
-        this.exit        = new Label(tryNode.getExit());
+        this.body = body;
+        this.catchBlocks = catchBlocks;
+        this.finallyBody = finallyBody;
+        this.exit = new Label(tryNode.exit);
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new TryNode(this, cs);
+    public Node ensureUniqueLabels(final LexicalContext lc) {
+        //try nodes are never in lex context
+        return new TryNode(this, body, catchBlocks, finallyBody);
+    }
+
+    @Override
+    public boolean isTerminal() {
+        if (body.isTerminal()) {
+            for (final Block catchBlock : getCatchBlocks()) {
+                if (!catchBlock.isTerminal()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
     }
 
     /**
@@ -101,21 +108,16 @@
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterTryNode(this) != null) {
-            // Need to do first for termination analysis.
-            if (finallyBody != null) {
-                finallyBody = (Block)finallyBody.accept(visitor);
-            }
-
-            body = (Block)body.accept(visitor);
-
-            final List<Block> newCatchBlocks = new ArrayList<>(catchBlocks.size());
-            for (final Block catchBlock : catchBlocks) {
-                newCatchBlocks.add((Block)catchBlock.accept(visitor));
-            }
-            this.catchBlocks = newCatchBlocks;
-
-            return visitor.leaveTryNode(this);
+        if (visitor.enterTryNode(this)) {
+            // Need to do finallybody first for termination analysis. TODO still necessary?
+            final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);
+            final Block newBody        = (Block)body.accept(visitor);
+            return visitor.leaveTryNode(
+                setBody(newBody).
+                setFinallyBody(newFinallyBody).
+                setCatchBlocks(Node.accept(visitor, Block.class, catchBlocks)).
+                setException(exception).
+                setFinallyCatchAll(finallyCatchAll));
         }
 
         return this;
@@ -123,7 +125,7 @@
 
     @Override
     public void toString(final StringBuilder sb) {
-        sb.append("try");
+        sb.append("try ");
     }
 
     /**
@@ -137,9 +139,13 @@
     /**
      * Reset the body of this try block
      * @param body new body
+     * @return new TryNode or same if unchanged
      */
-    public void setBody(final Block body) {
-        this.body = body;
+    public TryNode setBody(final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return new TryNode(this,  body, catchBlocks, finallyBody);
     }
 
     /**
@@ -151,16 +157,7 @@
         for (final Block catchBlock : catchBlocks) {
             catches.add((CatchNode)catchBlock.getStatements().get(0));
         }
-        return catches;
-    }
-
-    /**
-     * Returns true if the specified block is the body of this try block, or any of its catch blocks.
-     * @param block the block
-     * @return true if the specified block is the body of this try block, or any of its catch blocks.
-     */
-    public boolean isChildBlock(Block block) {
-        return body == block || catchBlocks.contains(block);
+        return Collections.unmodifiableList(catches);
     }
 
     /**
@@ -174,9 +171,13 @@
     /**
      * Set the catch blocks of this try
      * @param catchBlocks list of catch blocks
+     * @return new TryNode or same if unchanged
      */
-    public void setCatchBlocks(final List<Block> catchBlocks) {
-        this.catchBlocks = catchBlocks;
+    public TryNode setCatchBlocks(final List<Block> catchBlocks) {
+        if (this.catchBlocks == catchBlocks) {
+            return this;
+        }
+        return new TryNode(this, body, catchBlocks, finallyBody);
     }
 
     /**
@@ -190,9 +191,11 @@
     /**
      * Set the exception symbol for this try block
      * @param exception a symbol for the compiler to store the exception in
+     * @return new TryNode or same if unchanged
      */
-    public void setException(final Symbol exception) {
+    public TryNode setException(final Symbol exception) {
         this.exception = exception;
+        return this;
     }
 
     /**
@@ -207,9 +210,13 @@
      * If a finally block exists, the synthetic catchall needs another symbol to
      * store its throwable
      * @param finallyCatchAll a symbol for the finally catch all exception
+     * @return new TryNode or same if unchanged
+     *
+     * TODO can this still be stateful?
      */
-    public void setFinallyCatchAll(final Symbol finallyCatchAll) {
+    public TryNode setFinallyCatchAll(final Symbol finallyCatchAll) {
         this.finallyCatchAll = finallyCatchAll;
+        return this;
     }
 
     /**
@@ -221,14 +228,6 @@
     }
 
     /**
-     * Set the exit label for this try block
-     * @param exit label
-     */
-    public void setExit(final Label exit) {
-        this.exit = exit;
-    }
-
-    /**
      * Get the body of the finally clause for this try
      * @return finally body, or null if no finally
      */
@@ -239,24 +238,12 @@
     /**
      * Set the finally body of this try
      * @param finallyBody new finally body
-     */
-    public void setFinallyBody(final Block finallyBody) {
-        this.finallyBody = finallyBody;
-    }
-
-    /**
-     * Get next try node in try chain
-     * @return next try node
+     * @return new TryNode or same if unchanged
      */
-    public TryNode getNext() {
-        return next;
-    }
-
-    /**
-     * Set next try node in try chain
-     * @param next next try node
-     */
-    public void setNext(final TryNode next) {
-        this.next = next;
+    public TryNode setFinallyBody(final Block finallyBody) {
+        if (this.finallyBody == finallyBody) {
+            return this;
+        }
+        return new TryNode(this, body, catchBlocks, finallyBody);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java	Thu May 16 11:47:51 2013 +0100
@@ -31,6 +31,7 @@
 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
 
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
@@ -39,9 +40,10 @@
 /**
  * UnaryNode nodes represent single operand operations.
  */
-public class UnaryNode extends Node implements Assignment<Node> {
+@Immutable
+public final class UnaryNode extends Node implements Assignment<Node> {
     /** Right hand side argument. */
-    private Node rhs;
+    private final Node rhs;
 
     /**
      * Constructor
@@ -51,23 +53,26 @@
      * @param rhs    expression
      */
     public UnaryNode(final Source source, final long token, final Node rhs) {
-        super(source, token, Token.descPosition(token));
-
-        this.start  = Math.min(rhs.getStart(), Token.descPosition(token));
-        this.finish = Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish());
-        this.rhs    = rhs;
+        this(source, token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs);
     }
 
     /**
-     * Copy constructor
-     *
-     * @param unaryNode source node
-     * @param cs        copy state
+     * Constructor
+     * @param source the source
+     * @param token  token
+     * @param start  start
+     * @param finish finish
+     * @param rhs    expression
      */
-    protected UnaryNode(final UnaryNode unaryNode, final CopyState cs) {
+    public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) {
+        super(source, token, start, finish);
+        this.rhs = rhs;
+    }
+
+
+    private UnaryNode(final UnaryNode unaryNode, final Node rhs) {
         super(unaryNode);
-
-        this.rhs = cs.existingOrCopy(unaryNode.rhs);
+        this.rhs = rhs;
     }
 
     /**
@@ -113,31 +118,13 @@
         return getAssignmentDest();
     }
 
-    @Override
-    public boolean equals(final Object other) {
-        if (!super.equals(other)) {
-            return false;
-        }
-        return rhs.equals(((UnaryNode)other).rhs());
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode() ^ rhs().hashCode();
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new UnaryNode(this, cs);
-    }
-
     /**
      * Assist in IR navigation.
      * @param visitor IR navigating visitor.
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterUnaryNode(this) != null) {
+        if (visitor.enterUnaryNode(this)) {
             return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
         }
 
@@ -219,9 +206,9 @@
      * @return a node equivalent to this one except for the requested change.
      */
     public UnaryNode setRHS(final Node rhs) {
-        if(this.rhs == rhs) return this;
-        final UnaryNode n = (UnaryNode)clone();
-        n.rhs = rhs;
-        return n;
+        if (this.rhs == rhs) {
+            return this;
+        }
+        return new UnaryNode(this, rhs);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,21 +25,31 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Node represents a var/let declaration.
  */
-public class VarNode extends Node implements Assignment<IdentNode> {
+@Immutable
+public final class VarNode extends Node implements Assignment<IdentNode> {
     /** Var name. */
-    private IdentNode name;
+    private final IdentNode name;
 
     /** Initialization expression. */
-    private Node init;
+    private final Node init;
 
     /** Is this a var statement (as opposed to a "var" in a for loop statement) */
-    private final boolean isStatement;
+    private final int flags;
+
+    /** Flag that determines if this function node is a statement */
+    public static final int IS_STATEMENT = 1 << 0;
+
+    /** Flag that determines if this is the last function declaration in a function
+     *  This is used to micro optimize the placement of return value assignments for
+     *  a program node */
+    public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 1;
 
     /**
      * Constructor
@@ -51,7 +61,14 @@
      * @param init   init node or null if just a declaration
      */
     public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
-        this(source, token, finish, name, init, true);
+        this(source, token, finish, name, init, IS_STATEMENT);
+    }
+
+    private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) {
+        super(varNode);
+        this.name = init == null ? name : name.setIsInitializedHere();
+        this.init = init;
+        this.flags = flags;
     }
 
     /**
@@ -62,28 +79,14 @@
      * @param finish finish
      * @param name   name of variable
      * @param init   init node or null if just a declaration
-     * @param isStatement if this is a var statement (true), or a for-loop initializer (false)
+     * @param flags  flags
      */
-    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) {
+    public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) {
         super(source, token, finish);
 
         this.name  = init == null ? name : name.setIsInitializedHere();
         this.init  = init;
-        this.isStatement = isStatement;
-    }
-
-
-    private VarNode(final VarNode varNode, final CopyState cs) {
-        super(varNode);
-
-        this.name = (IdentNode)cs.existingOrCopy(varNode.name);
-        this.init = cs.existingOrCopy(varNode.init);
-        this.isStatement = varNode.isStatement;
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new VarNode(this, cs);
+        this.flags = flags;
     }
 
     @Override
@@ -115,45 +118,17 @@
     }
 
     /**
-     * Test to see if two VarNodes are the same.
-     * @param other Other VarNode.
-     * @return True if the VarNodes are the same.
-     */
-    @Override
-    public boolean equals(final Object other) {
-        if (other instanceof VarNode) {
-            final VarNode otherNode    = (VarNode)other;
-            final boolean nameMatches  = name.equals(otherNode.name);
-            if (hasInit() != otherNode.hasInit()) {
-                return false;
-            } else if (init == null) {
-                return nameMatches;
-            } else {
-                return nameMatches && init.equals(otherNode.init);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return name.hashCode() ^ (init == null ? 0 : init.hashCode());
-    }
-
-    /**
      * Assist in IR navigation.
      * @param visitor IR navigating visitor.
      */
     @Override
     public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterVarNode(this) != null) {
+        if (visitor.enterVarNode(this)) {
             final IdentNode newName = (IdentNode)name.accept(visitor);
-            final Node newInit = init == null ? null : init.accept(visitor);
-            final VarNode newThis;
-            if(name != newName || init != newInit) {
-                newThis = (VarNode)clone();
-                newThis.init = newInit;
-                newThis.name = newInit == null ? newName : newName.setIsInitializedHere();
+            final Node      newInit = init == null ? null : init.accept(visitor);
+            final VarNode   newThis;
+            if (name != newName || init != newInit) {
+                newThis = new VarNode(this, newName, newInit, flags);
             } else {
                 newThis = this;
             }
@@ -187,10 +162,10 @@
      * @return a node equivalent to this one except for the requested change.
      */
     public VarNode setInit(final Node init) {
-        if(this.init == init) return this;
-        final VarNode n = (VarNode)clone();
-        n.init = init;
-        return n;
+        if (this.init == init) {
+            return this;
+        }
+        return new VarNode(this, name, init, flags);
     }
 
     /**
@@ -204,12 +179,38 @@
     /**
      * Reset the identifier for this VarNode
      * @param name new IdentNode representing the variable being set or declared
+     * @return a node equivalent to this one except for the requested change.
      */
-    private VarNode setName(final IdentNode name) {
-        if(this.name == name) return this;
-        final VarNode n = (VarNode)clone();
-        n.name = name;
-        return n;
+    public VarNode setName(final IdentNode name) {
+        if (this.name == name) {
+            return this;
+        }
+        return new VarNode(this, name, init, flags);
+    }
+
+    private VarNode setFlags(final int flags) {
+        if (this.flags == flags) {
+            return this;
+        }
+        return new VarNode(this, name, init, flags);
+    }
+
+    /**
+     * Check if a flag is set for this var node
+     * @param flag flag
+     * @return true if flag is set
+     */
+    public boolean getFlag(final int flag) {
+        return (flags & flag) == flag;
+    }
+
+    /**
+     * Set a flag for this var node
+     * @param flag flag
+     * @return new node if flags changed, same otherwise
+     */
+    public VarNode setFlag(final int flag) {
+        return setFlags(flags | flag);
     }
 
     /**
@@ -217,7 +218,7 @@
      * @return true if this is a var statement (as opposed to a var initializer in a for loop).
      */
     public boolean isStatement() {
-        return isStatement;
+        return (flags & IS_STATEMENT) != 0;
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,7 +25,7 @@
 
 package jdk.nashorn.internal.ir;
 
-import jdk.nashorn.internal.codegen.Label;
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
@@ -33,130 +33,126 @@
  * IR representation for a WHILE statement. This is the superclass of all
  * loop nodes
  */
-public class WhileNode extends BreakableNode {
-    /** Test expression. */
-    protected Node test;
+@Immutable
+public final class WhileNode extends LoopNode {
 
-    /** For body. */
-    protected Block body;
-
-    /** loop continue label. */
-    protected Label continueLabel;
+    /** is this a do while node ? */
+    private final boolean isDoWhile;
 
     /**
      * Constructor
      *
-     * @param source  the source
-     * @param token   token
-     * @param finish  finish
+     * @param source    the source
+     * @param token     token
+     * @param finish    finish
+     * @param isDoWhile is this a do while loop?
      */
-    public WhileNode(final Source source, final long token, final int finish) {
-        super(source, token, finish);
-
-        this.breakLabel    = new Label("while_break");
-        this.continueLabel = new Label("while_continue");
+    public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) {
+        super(source, token, finish, null, null, false);
+        this.isDoWhile = isDoWhile;
     }
 
     /**
-     * Copy constructor
+     * Internal copy constructor
      *
-     * @param whileNode source node
-     * @param cs        copy state
+     * @param whileNode while node
+     * @param test      test
+     * @param body      body
+     * @param controlFlowEscapes control flow escapes?
      */
-    protected WhileNode(final WhileNode whileNode, final CopyState cs) {
-        super(whileNode);
-
-        this.test          = cs.existingOrCopy(whileNode.test);
-        this.body          = (Block)cs.existingOrCopy(whileNode.body);
-        this.breakLabel    = new Label(whileNode.breakLabel);
-        this.continueLabel = new Label(whileNode.continueLabel);
+    protected WhileNode(final WhileNode whileNode, final Node test, final Block body, final boolean controlFlowEscapes) {
+        super(whileNode, test, body, controlFlowEscapes);
+        this.isDoWhile = whileNode.isDoWhile;
     }
 
     @Override
-    protected Node copy(final CopyState cs) {
-        return new WhileNode(this, cs);
+    public Node ensureUniqueLabels(final LexicalContext lc) {
+        return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes));
+    }
+
+    @Override
+    public boolean hasGoto() {
+        return test == null;
     }
 
     @Override
-    public boolean isLoop() {
-        return true;
-    }
+    protected Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterWhileNode(this)) {
+            if (isDoWhile()) {
+                return visitor.leaveWhileNode(
+                        setTest(lc, test.accept(visitor)).
+                        setBody(lc, (Block)body.accept(visitor)));
+            }
+            return visitor.leaveWhileNode(
+                    setBody(lc, (Block)body.accept(visitor)).
+                    setTest(lc, test.accept(visitor)));
 
-    /**
-     * Assist in IR navigation.
-     * @param visitor IR navigating visitor.
-     */
-    @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterWhileNode(this) != null) {
-            test = test.accept(visitor);
-            body = (Block)body.accept(visitor);
-
-            return visitor.leaveWhileNode(this);
         }
         return this;
     }
 
     @Override
-    public void toString(final StringBuilder sb) {
-        sb.append("while (");
-        test.toString(sb);
-        sb.append(')');
+    public Node getTest() {
+        return test;
     }
 
-    /**
-     * Get the loop body
-     * @return body
-     */
+    @Override
+    public WhileNode setTest(final LexicalContext lc, final Node test) {
+        if (this.test == test) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes));
+    }
+
+    @Override
     public Block getBody() {
         return body;
     }
 
-    /**
-     * Reset the loop body
-     * @param body new body
-     */
-    public void setBody(final Block body) {
-        this.body = body;
+    @Override
+    public WhileNode setBody(final LexicalContext lc, final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes));
     }
 
-    /**
-     * Set the break label (described in {@link WhileNode#getBreakLabel()} for this while node
-     * @param breakLabel break label
-     */
-    public void setBreakLabel(final Label breakLabel) {
-        this.breakLabel = breakLabel;
+    @Override
+    public WhileNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes) {
+        if (this.controlFlowEscapes == controlFlowEscapes) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes));
     }
 
     /**
-     * Get the continue label for this while node, i.e. location to go to on continue
-     * @return continue label
+     * Check if this is a do while loop or a normal while loop
+     * @return true if do while
      */
-    public Label getContinueLabel() {
-        return continueLabel;
-    }
-
-    /**
-     * Set the continue label (described in {@link WhileNode#getContinueLabel()} for this while node
-     * @param continueLabel continue label
-     */
-    public void setContinueLabel(final Label continueLabel) {
-        this.continueLabel = continueLabel;
+    public boolean isDoWhile() {
+        return isDoWhile;
     }
 
-    /**
-     * Get the test expression for this loop, that upon evaluation to true does another iteration
-     * @return test expression
-     */
-    public Node getTest() {
-        return test;
+    @Override
+    public void toString(final StringBuilder sb) {
+        if (isDoWhile()) {
+            sb.append("do {");
+            body.toString(sb);
+            sb.append("} while (");
+            test.toString(sb);
+            sb.append(')');
+        } else {
+            sb.append("while (");
+            test.toString(sb);
+            sb.append(')');
+        }
     }
 
-    /**
-     * Set the test expression for this loop
-     * @param test test expression, null if infinite loop
-     */
-    public void setTest(final Node test) {
-        this.test = test;
+    @Override
+    public boolean mustEnter() {
+        if (isDoWhile()) {
+            return true;
+        }
+        return test == null;
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/WithNode.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/WithNode.java	Thu May 16 11:47:51 2013 +0100
@@ -25,18 +25,20 @@
 
 package jdk.nashorn.internal.ir;
 
+import jdk.nashorn.internal.ir.annotations.Immutable;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Source;
 
 /**
  * IR representation for {@code with} statements.
  */
-public class WithNode extends Node {
+@Immutable
+public final class WithNode extends LexicalContextNode {
    /** This expression. */
-    private Node expression;
+    private final Node expression;
 
     /** Statements. */
-    private Block body;
+    private final Block body;
 
     /**
      * Constructor
@@ -44,42 +46,39 @@
      * @param source     the source
      * @param token      token
      * @param finish     finish
-     * @param expression expression in parenthesis
-     * @param body       with node body
      */
-    public WithNode(final Source source, final long token, final int finish, final Node expression, final Block body) {
+    public WithNode(final Source source, final long token, final int finish) {
         super(source, token, finish);
 
+        this.expression = null;
+        this.body       = null;
+    }
+
+    private WithNode(final WithNode node, final Node expression, final Block body) {
+        super(node);
+
         this.expression = expression;
         this.body       = body;
     }
 
-    private WithNode(final WithNode withNode, final CopyState cs) {
-        super(withNode);
-
-        this.expression = cs.existingOrCopy(withNode.expression);
-        this.body       = (Block)cs.existingOrCopy(withNode.body);
-    }
-
-    @Override
-    protected Node copy(final CopyState cs) {
-        return new WithNode(this, cs);
-    }
-
     /**
      * Assist in IR navigation.
      *
      * @param visitor IR navigating visitor.
      */
     @Override
-    public Node accept(final NodeVisitor visitor) {
-        if (visitor.enterWithNode(this) != null) {
-            expression = expression.accept(visitor);
-            body = (Block)body.accept(visitor);
-            return visitor.leaveWithNode(this);
+    public Node accept(final LexicalContext lc, final NodeVisitor visitor) {
+        if (visitor.enterWithNode(this)) {
+             return visitor.leaveWithNode(
+                setExpression(lc, expression.accept(visitor)).
+                setBody(lc, (Block)body.accept(visitor)));
         }
+        return this;
+    }
 
-        return this;
+    @Override
+    public boolean isTerminal() {
+        return body.isTerminal();
     }
 
     @Override
@@ -99,10 +98,15 @@
 
     /**
      * Reset the body of this with node
+     * @param lc lexical context
      * @param body new body
+     * @return new or same withnode
      */
-    public void setBody(final Block body) {
-        this.body = body;
+    public WithNode setBody(final LexicalContext lc, final Block body) {
+        if (this.body == body) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new WithNode(this, expression, body));
     }
 
     /**
@@ -115,10 +119,15 @@
 
     /**
      * Reset the expression of this with node
+     * @param lc lexical context
      * @param expression new expression
+     * @return new or same withnode
      */
-    public void setExpression(final Node expression) {
-        this.expression = expression;
+    public WithNode setExpression(final LexicalContext lc, final Node expression) {
+        if (this.expression == expression) {
+            return this;
+        }
+        return Node.replaceInLexicalContext(lc, this, new WithNode(this, expression, body));
     }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/annotations/Immutable.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * 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.ir.annotations;
+
+/**
+ * Tag for nodes that are immutable. To be immutable all fields must be
+ * final and copy on write semantics must be in place
+ */
+public @interface Immutable {
+    //empty
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/ASTWriter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/ASTWriter.java	Thu May 16 11:47:51 2013 +0100
@@ -33,7 +33,9 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+
 import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.annotations.Ignore;
@@ -113,6 +115,10 @@
             type += "#" + node.getSymbol();
         }
 
+        if (node instanceof Block && ((Block)node).needsScope()) {
+            type += " <scope>";
+        }
+
         final List<Field> children = new LinkedList<>();
 
         if (!isReference) {
@@ -121,10 +127,6 @@
 
         String status = "";
 
-        if (node.shouldDiscard()) {
-            status += " Discard";
-        }
-
         if (node.isTerminal()) {
             status += " Terminal";
         }
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java	Thu May 16 11:47:51 2013 +0100
@@ -36,7 +36,6 @@
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -88,7 +87,7 @@
         final Parser       parser     = new Parser(env, new Source(name, code), new Context.ThrowErrorManager(), env._strict);
         final JSONWriter   jsonWriter = new JSONWriter(includeLoc);
         try {
-            final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.tag());
+            final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.symbolName());
             functionNode.accept(jsonWriter);
             return jsonWriter.getString();
         } catch (final ParserException e) {
@@ -98,11 +97,16 @@
     }
 
     @Override
-    protected Node enterDefault(final Node node) {
+    protected boolean enterDefault(final Node node) {
         objectStart();
         location(node);
 
-        return node;
+        return true;
+    }
+
+    private boolean leave() {
+        objectEnd();
+        return false;
     }
 
     @Override
@@ -112,7 +116,7 @@
     }
 
     @Override
-    public Node enterAccessNode(final AccessNode accessNode) {
+    public boolean enterAccessNode(final AccessNode accessNode) {
         enterDefault(accessNode);
 
         type("MemberExpression");
@@ -128,11 +132,11 @@
 
         property("computed", false);
 
-        return leaveDefault(accessNode);
+        return leave();
     }
 
     @Override
-    public Node enterBlock(final Block block) {
+    public boolean enterBlock(final Block block) {
         enterDefault(block);
 
         type("BlockStatement");
@@ -140,21 +144,21 @@
 
         array("body", block.getStatements());
 
-        return leaveDefault(block);
+        return leave();
     }
 
     private static boolean isLogical(final TokenType tt) {
         switch (tt) {
-            case AND:
-            case OR:
-                return true;
-            default:
-                return false;
+        case AND:
+        case OR:
+            return true;
+        default:
+            return false;
         }
     }
 
     @Override
-    public Node enterBinaryNode(final BinaryNode binaryNode) {
+    public boolean enterBinaryNode(final BinaryNode binaryNode) {
         enterDefault(binaryNode);
 
         final String name;
@@ -179,29 +183,29 @@
         property("right");
         binaryNode.rhs().accept(this);
 
-        return leaveDefault(binaryNode);
+        return leave();
     }
 
     @Override
-    public Node enterBreakNode(final BreakNode breakNode) {
+    public boolean enterBreakNode(final BreakNode breakNode) {
         enterDefault(breakNode);
 
         type("BreakStatement");
         comma();
 
-        final LabelNode label = breakNode.getLabel();
+        final IdentNode label = breakNode.getLabel();
         if (label != null) {
-            property("label", label.getLabel().getName());
+            property("label", label.getName());
         } else {
             property("label");
             nullValue();
         }
 
-        return leaveDefault(breakNode);
+        return leave();
     }
 
     @Override
-    public Node enterCallNode(final CallNode callNode) {
+    public boolean enterCallNode(final CallNode callNode) {
         enterDefault(callNode);
 
         type("CallExpression");
@@ -213,11 +217,11 @@
 
         array("arguments", callNode.getArgs());
 
-        return leaveDefault(callNode);
+        return leave();
     }
 
     @Override
-    public Node enterCaseNode(final CaseNode caseNode) {
+    public boolean enterCaseNode(final CaseNode caseNode) {
         enterDefault(caseNode);
 
         type("SwitchCase");
@@ -234,11 +238,11 @@
 
         array("consequent", caseNode.getBody().getStatements());
 
-        return leaveDefault(caseNode);
+        return leave();
     }
 
     @Override
-    public Node enterCatchNode(final CatchNode catchNode) {
+    public boolean enterCatchNode(final CatchNode catchNode) {
         enterDefault(catchNode);
 
         type("CatchClause");
@@ -260,55 +264,38 @@
         property("body");
         catchNode.getBody().accept(this);
 
-        return leaveDefault(catchNode);
+        return leave();
     }
 
     @Override
-    public Node enterContinueNode(final ContinueNode continueNode) {
+    public boolean enterContinueNode(final ContinueNode continueNode) {
         enterDefault(continueNode);
 
         type("ContinueStatement");
         comma();
 
-        final LabelNode label = continueNode.getLabel();
+        final IdentNode label = continueNode.getLabel();
         if (label != null) {
-            property("label", label.getLabel().getName());
+            property("label", label.getName());
         } else {
             property("label");
             nullValue();
         }
 
-        return leaveDefault(continueNode);
+        return leave();
     }
 
     @Override
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        enterDefault(doWhileNode);
-
-        type("DoWhileStatement");
-        comma();
-
-        property("body");
-        doWhileNode.getBody().accept(this);
-        comma();
-
-        property("test");
-        doWhileNode.getTest().accept(this);
-
-        return leaveDefault(doWhileNode);
-    }
-
-    @Override
-    public Node enterEmptyNode(final EmptyNode emptyNode) {
+    public boolean enterEmptyNode(final EmptyNode emptyNode) {
         enterDefault(emptyNode);
 
         type("EmptyStatement");
 
-        return leaveDefault(emptyNode);
+        return leave();
     }
 
     @Override
-    public Node enterExecuteNode(final ExecuteNode executeNode) {
+    public boolean enterExecuteNode(final ExecuteNode executeNode) {
         enterDefault(executeNode);
 
         type("ExpressionStatement");
@@ -317,11 +304,11 @@
         property("expression");
         executeNode.getExpression().accept(this);
 
-        return leaveDefault(executeNode);
+        return leave();
     }
 
     @Override
-    public Node enterForNode(final ForNode forNode) {
+    public boolean enterForNode(final ForNode forNode) {
         enterDefault(forNode);
 
         if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) {
@@ -380,11 +367,11 @@
             forNode.getBody().accept(this);
         }
 
-        return leaveDefault(forNode);
+        return leave();
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
         enterDefault(functionNode);
 
         final boolean program = functionNode.isProgram();
@@ -419,7 +406,7 @@
         }
 
         // body consists of nested functions and statements
-        final List<Node> stats = functionNode.getStatements();
+        final List<Node> stats = functionNode.getBody().getStatements();
         final int size = stats.size();
         int idx = 0;
         arrayStart("body");
@@ -435,11 +422,11 @@
         }
         arrayEnd();
 
-        return leaveDefault(functionNode);
+        return leave();
     }
 
     @Override
-    public Node enterIdentNode(final IdentNode identNode) {
+    public boolean enterIdentNode(final IdentNode identNode) {
         enterDefault(identNode);
 
         final String name = identNode.getName();
@@ -451,11 +438,11 @@
             property("name", identNode.getName());
         }
 
-        return leaveDefault(identNode);
+        return leave();
     }
 
     @Override
-    public Node enterIfNode(final IfNode ifNode) {
+    public boolean enterIfNode(final IfNode ifNode) {
         enterDefault(ifNode);
 
         type("IfStatement");
@@ -477,11 +464,11 @@
             nullValue();
         }
 
-        return leaveDefault(ifNode);
+        return leave();
     }
 
     @Override
-    public Node enterIndexNode(final IndexNode indexNode) {
+    public boolean enterIndexNode(final IndexNode indexNode) {
         enterDefault(indexNode);
 
         type("MemberExpression");
@@ -497,11 +484,11 @@
 
         property("computed", true);
 
-        return leaveDefault(indexNode);
+        return leave();
     }
 
     @Override
-    public Node enterLabelNode(final LabelNode labelNode) {
+    public boolean enterLabelNode(final LabelNode labelNode) {
         enterDefault(labelNode);
 
         type("LabeledStatement");
@@ -514,17 +501,17 @@
         property("body");
         labelNode.getBody().accept(this);
 
-        return leaveDefault(labelNode);
+        return leave();
     }
 
     @Override
-    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
-        return null;
+    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
+        return false;
     }
 
     @SuppressWarnings("rawtypes")
     @Override
-    public Node enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         enterDefault(literalNode);
 
         if (literalNode instanceof LiteralNode.ArrayLiteralNode) {
@@ -556,11 +543,11 @@
             }
         }
 
-        return leaveDefault(literalNode);
+        return leave();
     }
 
     @Override
-    public Node enterObjectNode(final ObjectNode objectNode) {
+    public boolean enterObjectNode(final ObjectNode objectNode) {
         enterDefault(objectNode);
 
         type("ObjectExpression");
@@ -568,11 +555,11 @@
 
         array("properties", objectNode.getElements());
 
-        return leaveDefault(objectNode);
+        return leave();
     }
 
     @Override
-    public Node enterPropertyNode(final PropertyNode propertyNode) {
+    public boolean enterPropertyNode(final PropertyNode propertyNode) {
         final Node key = propertyNode.getKey();
 
         final Node value = propertyNode.getValue();
@@ -634,11 +621,11 @@
             }
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterReturnNode(final ReturnNode returnNode) {
+    public boolean enterReturnNode(final ReturnNode returnNode) {
         enterDefault(returnNode);
 
         type("ReturnStatement");
@@ -652,31 +639,29 @@
             nullValue();
         }
 
-        return leaveDefault(returnNode);
+        return leave();
     }
 
     @Override
-    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
+    public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
         final RuntimeNode.Request req = runtimeNode.getRequest();
 
         if (req == RuntimeNode.Request.DEBUGGER) {
             enterDefault(runtimeNode);
-
             type("DebuggerStatement");
-
-            return leaveDefault(runtimeNode);
+            return leave();
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterSplitNode(final SplitNode splitNode) {
-        return null;
+    public boolean enterSplitNode(final SplitNode splitNode) {
+        return false;
     }
 
     @Override
-    public Node enterSwitchNode(final SwitchNode switchNode) {
+    public boolean enterSwitchNode(final SwitchNode switchNode) {
         enterDefault(switchNode);
 
         type("SwitchStatement");
@@ -688,11 +673,11 @@
 
         array("cases", switchNode.getCases());
 
-        return leaveDefault(switchNode);
+        return leave();
     }
 
     @Override
-    public Node enterTernaryNode(final TernaryNode ternaryNode) {
+    public boolean enterTernaryNode(final TernaryNode ternaryNode) {
         enterDefault(ternaryNode);
 
         type("ConditionalExpression");
@@ -709,11 +694,11 @@
         property("alternate");
         ternaryNode.third().accept(this);
 
-        return leaveDefault(ternaryNode);
+        return leave();
     }
 
     @Override
-    public Node enterThrowNode(final ThrowNode throwNode) {
+    public boolean enterThrowNode(final ThrowNode throwNode) {
         enterDefault(throwNode);
 
         type("ThrowStatement");
@@ -722,11 +707,11 @@
         property("argument");
         throwNode.getExpression().accept(this);
 
-        return leaveDefault(throwNode);
+        return leave();
     }
 
     @Override
-    public Node enterTryNode(final TryNode tryNode) {
+    public boolean enterTryNode(final TryNode tryNode) {
         enterDefault(tryNode);
 
         type("TryStatement");
@@ -747,11 +732,11 @@
             nullValue();
         }
 
-        return leaveDefault(tryNode);
+        return leave();
     }
 
     @Override
-    public Node enterUnaryNode(final UnaryNode unaryNode) {
+    public boolean enterUnaryNode(final UnaryNode unaryNode) {
         enterDefault(unaryNode);
 
         final TokenType tokenType = unaryNode.tokenType();
@@ -769,25 +754,25 @@
             final boolean prefix;
             final String operator;
             switch (tokenType) {
-                case INCPOSTFIX:
-                    prefix = false;
-                    operator = "++";
-                    break;
-                case DECPOSTFIX:
-                    prefix = false;
-                    operator = "--";
-                    break;
-                case INCPREFIX:
-                    operator = "++";
-                    prefix = true;
-                    break;
-                case DECPREFIX:
-                    operator = "--";
-                    prefix = true;
-                    break;
-                default:
-                    prefix = false;
-                    operator = tokenType.getName();
+            case INCPOSTFIX:
+                prefix = false;
+                operator = "++";
+                break;
+            case DECPOSTFIX:
+                prefix = false;
+                operator = "--";
+                break;
+            case INCPREFIX:
+                operator = "++";
+                prefix = true;
+                break;
+            case DECPREFIX:
+                operator = "--";
+                prefix = true;
+                break;
+            default:
+                prefix = false;
+                operator = tokenType.getName();
             }
 
             type(unaryNode.isAssignment()? "UpdateExpression" : "UnaryExpression");
@@ -803,11 +788,11 @@
             unaryNode.rhs().accept(this);
         }
 
-        return leaveDefault(unaryNode);
+        return leave();
     }
 
     @Override
-    public Node enterVarNode(final VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         enterDefault(varNode);
 
         type("VariableDeclaration");
@@ -839,28 +824,37 @@
         // declarations
         arrayEnd();
 
-        return leaveDefault(varNode);
+        return leave();
     }
 
     @Override
-    public Node enterWhileNode(final WhileNode whileNode) {
+    public boolean enterWhileNode(final WhileNode whileNode) {
         enterDefault(whileNode);
 
-        type("WhileStatement");
+        type(whileNode.isDoWhile() ? "DoWhileStatement" : "WhileStatement");
         comma();
 
-        property("test");
-        whileNode.getTest().accept(this);
-        comma();
+        if (whileNode.isDoWhile()) {
+            property("body");
+            whileNode.getBody().accept(this);
+            comma();
 
-        property("block");
-        whileNode.getBody().accept(this);
+            property("test");
+            whileNode.getTest().accept(this);
+        } else {
+            property("test");
+            whileNode.getTest().accept(this);
+            comma();
 
-        return leaveDefault(whileNode);
+            property("block");
+            whileNode.getBody().accept(this);
+        }
+
+        return leave();
     }
 
     @Override
-    public Node enterWithNode(final WithNode withNode) {
+    public boolean enterWithNode(final WithNode withNode) {
         enterDefault(withNode);
 
         type("WithStatement");
@@ -873,8 +867,8 @@
         property("body");
         withNode.getBody().accept(this);
 
-        return leaveDefault(withNode);
-    }
+        return leave();
+   }
 
     // Internals below
 
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java	Thu May 16 11:47:51 2013 +0100
@@ -26,30 +26,22 @@
 package jdk.nashorn.internal.ir.debug;
 
 import java.util.List;
-import jdk.nashorn.internal.ir.AccessNode;
+
+import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
-import jdk.nashorn.internal.ir.BreakNode;
-import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
-import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReturnNode;
-import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.SplitNode;
 import jdk.nashorn.internal.ir.SwitchNode;
 import jdk.nashorn.internal.ir.Symbol;
-import jdk.nashorn.internal.ir.ThrowNode;
 import jdk.nashorn.internal.ir.TryNode;
-import jdk.nashorn.internal.ir.UnaryNode;
 import jdk.nashorn.internal.ir.VarNode;
 import jdk.nashorn.internal.ir.WhileNode;
 import jdk.nashorn.internal.ir.WithNode;
@@ -136,21 +128,20 @@
     /*
      * Visits.
      */
+
     @Override
-    public Node enterAccessNode(final AccessNode accessNode) {
-        accessNode.toString(sb);
-        return null;
+    public boolean enterDefault(final Node node) {
+        node.toString(sb);
+        return false;
     }
 
     @Override
-    public Node enterBlock(final Block block) {
+    public boolean enterBlock(final Block block) {
         sb.append(' ');
         sb.append('{');
 
         indent += TABWIDTH;
 
-        final boolean isFunction = block instanceof FunctionNode;
-
         final List<Node> statements = block.getStatements();
 
         boolean lastLineNumber = false;
@@ -161,14 +152,14 @@
                 indent();
             }
 
-            if (statement instanceof UnaryNode) {
-                statement.toString(sb);
-            } else {
-                statement.accept(this);
-            }
+            statement.accept(this);
 
             lastLineNumber = statement instanceof LineNumberNode;
 
+            if (statement instanceof FunctionNode) {
+                continue;
+            }
+
             final Symbol symbol = statement.getSymbol();
 
             if (symbol != null) {
@@ -200,72 +191,42 @@
         indent();
         sb.append("}");
 
-        if (isFunction) {
-            sb.append(EOLN);
-        }
-
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterBreakNode(final BreakNode breakNode) {
-        breakNode.toString(sb);
-        return null;
-    }
-
-    @Override
-    public Node enterCallNode(final CallNode callNode) {
-        callNode.toString(sb);
-        return null;
-    }
-
-    @Override
-    public Node enterContinueNode(final ContinueNode continueNode) {
-        continueNode.toString(sb);
-        return null;
+    public boolean enterBinaryNode(final BinaryNode binaryNode) {
+        binaryNode.lhs().accept(this);
+        sb.append(' ');
+        sb.append(binaryNode.tokenType());
+        sb.append(' ');
+        binaryNode.rhs().accept(this);
+        return false;
     }
 
     @Override
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        sb.append("do");
-        doWhileNode.getBody().accept(this);
-        sb.append(' ');
-        doWhileNode.toString(sb);
-
-        return null;
+    public boolean enterExecuteNode(final ExecuteNode executeNode) {
+        executeNode.getExpression().accept(this);
+        return false;
     }
 
     @Override
-    public Node enterExecuteNode(final ExecuteNode executeNode) {
-        final Node expression = executeNode.getExpression();
-
-        if (expression instanceof UnaryNode) {
-            expression.toString(sb);
-        } else {
-            expression.accept(this);
-        }
-
-        return null;
+    public boolean enterForNode(final ForNode forNode) {
+        forNode.toString(sb);
+        forNode.getBody().accept(this);
+        return false;
     }
 
     @Override
-    public Node enterForNode(final ForNode forNode) {
-        forNode.toString(sb);
-        forNode.getBody().accept(this);
-
-        return null;
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        functionNode.toString(sb);
+        enterBlock(functionNode.getBody());
+        sb.append(EOLN);
+        return false;
     }
 
     @Override
-    public Node enterFunctionNode(final FunctionNode functionNode) {
-        functionNode.toString(sb);
-        enterBlock(functionNode);
-
-        return null;
-    }
-
-    @Override
-    public Node enterIfNode(final IfNode ifNode) {
+    public boolean enterIfNode(final IfNode ifNode) {
         ifNode.toString(sb);
         ifNode.getPass().accept(this);
 
@@ -276,55 +237,36 @@
             fail.accept(this);
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterIndexNode(final IndexNode indexNode) {
-        indexNode.toString(sb);
-        return null;
-    }
-
-    @Override
-    public Node enterLabelNode(final LabelNode labeledNode) {
+    public boolean enterLabelNode(final LabelNode labeledNode) {
         indent -= TABWIDTH;
         indent();
         indent += TABWIDTH;
         labeledNode.toString(sb);
         labeledNode.getBody().accept(this);
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
+    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
         if (printLineNumbers) {
             lineNumberNode.toString(sb);
         }
 
-        return null;
-    }
-
-
-    @Override
-    public Node enterReturnNode(final ReturnNode returnNode) {
-        returnNode.toString(sb);
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
-        runtimeNode.toString(sb);
-        return null;
-    }
-
-    @Override
-    public Node enterSplitNode(final SplitNode splitNode) {
+    public boolean enterSplitNode(final SplitNode splitNode) {
         splitNode.toString(sb);
         sb.append(EOLN);
         indent += TABWIDTH;
         indent();
-        return splitNode;
+        return true;
     }
 
     @Override
@@ -337,7 +279,7 @@
     }
 
     @Override
-    public Node enterSwitchNode(final SwitchNode switchNode) {
+    public boolean enterSwitchNode(final SwitchNode switchNode) {
         switchNode.toString(sb);
         sb.append(" {");
 
@@ -357,24 +299,18 @@
         indent();
         sb.append("}");
 
-        return null;
-   }
-
-    @Override
-    public Node enterThrowNode(final ThrowNode throwNode) {
-        throwNode.toString(sb);
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterTryNode(final TryNode tryNode) {
+    public boolean enterTryNode(final TryNode tryNode) {
         tryNode.toString(sb);
         tryNode.getBody().accept(this);
 
         final List<Block> catchBlocks = tryNode.getCatchBlocks();
 
         for (final Block catchBlock : catchBlocks) {
-            final CatchNode catchNode = (CatchNode) catchBlock.getStatements().get(0);
+            final CatchNode catchNode = (CatchNode)catchBlock.getStatements().get(0);
             catchNode.toString(sb);
             catchNode.getBody().accept(this);
         }
@@ -386,35 +322,42 @@
             finallyBody.accept(this);
         }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterVarNode(final VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         sb.append("var ");
         varNode.getName().toString(sb);
         final Node init = varNode.getInit();
-        if(init != null) {
+        if (init != null) {
             sb.append(" = ");
             init.accept(this);
         }
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterWhileNode(final WhileNode whileNode) {
-        whileNode.toString(sb);
-        whileNode.getBody().accept(this);
+    public boolean enterWhileNode(final WhileNode whileNode) {
+        if (whileNode.isDoWhile()) {
+            sb.append("do");
+            whileNode.getBody().accept(this);
+            sb.append(' ');
+            whileNode.toString(sb);
+        } else {
+            whileNode.toString(sb);
+            whileNode.getBody().accept(this);
+        }
 
-        return null;
+        return false;
     }
 
     @Override
-    public Node enterWithNode(final WithNode withNode) {
+    public boolean enterWithNode(final WithNode withNode) {
         withNode.toString(sb);
         withNode.getBody().accept(this);
 
-        return null;
+        return false;
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Thu May 16 11:47:51 2013 +0100
@@ -25,9 +25,8 @@
 
 package jdk.nashorn.internal.ir.visitor;
 
-import jdk.nashorn.internal.codegen.CompileUnit;
-import jdk.nashorn.internal.codegen.MethodEmitter;
 import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.UnaryNode;
 
@@ -45,15 +44,14 @@
     /**
      * Constructor
      *
-     * @param compileUnit compile unit
-     * @param method      method emitter
+     * @param lc a custom lexical context
      */
-    public NodeOperatorVisitor(final CompileUnit compileUnit, final MethodEmitter method) {
-        super(compileUnit, method);
+    public NodeOperatorVisitor(final LexicalContext lc) {
+        super(lc);
     }
 
     @Override
-    public final Node enterUnaryNode(final UnaryNode unaryNode) {
+    public final boolean enterUnaryNode(final UnaryNode unaryNode) {
         switch (unaryNode.tokenType()) {
         case ADD:
             return enterADD(unaryNode);
@@ -119,7 +117,7 @@
     }
 
     @Override
-    public final Node enterBinaryNode(final BinaryNode binaryNode) {
+    public final boolean enterBinaryNode(final BinaryNode binaryNode) {
         switch (binaryNode.tokenType()) {
         case ADD:
             return enterADD(binaryNode);
@@ -287,17 +285,6 @@
     }
 
     /*
-    @Override
-    public Node enter(final TernaryNode ternaryNode) {
-        return enterDefault(ternaryNode);
-    }
-
-    @Override
-    public Node leave(final TernaryNode ternaryNode) {
-        return leaveDefault(ternaryNode);
-    }*/
-
-    /*
      * Unary entries and exists.
      */
 
@@ -305,9 +292,9 @@
      * Unary enter - callback for entering a unary +
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterADD(final UnaryNode unaryNode) {
+    public boolean enterADD(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -325,9 +312,9 @@
      * Unary enter - callback for entering a ~ operator
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBIT_NOT(final UnaryNode unaryNode) {
+    public boolean enterBIT_NOT(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -345,9 +332,9 @@
      * Unary enter - callback for entering a conversion
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCONVERT(final UnaryNode unaryNode) {
+    public boolean enterCONVERT(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -365,9 +352,9 @@
      * Unary enter - callback for entering a ++ or -- operator
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterDECINC(final UnaryNode unaryNode) {
+    public boolean enterDECINC(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -387,7 +374,7 @@
      * @param  unaryNode the node
      * @return processed node
      */
-    public Node enterDELETE(final UnaryNode unaryNode) {
+    public boolean enterDELETE(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -405,9 +392,9 @@
      * Unary enter - callback for entering a discard operator
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterDISCARD(final UnaryNode unaryNode) {
+    public boolean enterDISCARD(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -425,9 +412,9 @@
      * Unary enter - callback for entering a new operator
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterNEW(final UnaryNode unaryNode) {
+    public boolean enterNEW(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -445,9 +432,9 @@
      * Unary enter - callback for entering a ! operator
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterNOT(final UnaryNode unaryNode) {
+    public boolean enterNOT(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -465,9 +452,9 @@
      * Unary enter - callback for entering a unary -
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSUB(final UnaryNode unaryNode) {
+    public boolean enterSUB(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -485,9 +472,9 @@
      * Unary enter - callback for entering a typeof
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterTYPEOF(final UnaryNode unaryNode) {
+    public boolean enterTYPEOF(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -505,9 +492,9 @@
      * Unary enter - callback for entering a void
      *
      * @param  unaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterVOID(final UnaryNode unaryNode) {
+    public boolean enterVOID(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -525,9 +512,9 @@
      * Binary enter - callback for entering + operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterADD(final BinaryNode binaryNode) {
+    public boolean enterADD(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -545,9 +532,9 @@
      * Binary enter - callback for entering {@literal &&} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterAND(final BinaryNode binaryNode) {
+    public boolean enterAND(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -565,9 +552,9 @@
      * Binary enter - callback for entering an assignment
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN(final BinaryNode binaryNode) {
+    public boolean enterASSIGN(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -585,9 +572,9 @@
      * Binary enter - callback for entering += operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_ADD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_ADD(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -605,9 +592,9 @@
      * Binary enter - callback for entering {@literal &=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -625,9 +612,9 @@
      * Binary enter - callback for entering |= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -645,9 +632,9 @@
      * Binary enter - callback for entering ^= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -665,9 +652,9 @@
      * Binary enter - callback for entering /= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_DIV(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_DIV(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -685,9 +672,9 @@
      * Binary enter - callback for entering %= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_MOD(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MOD(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -705,9 +692,9 @@
      * Binary enter - callback for entering *= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_MUL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_MUL(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -725,9 +712,9 @@
      * Binary enter - callback for entering {@literal >>=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_SAR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SAR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -745,9 +732,9 @@
      * Binary enter - callback for entering a {@literal <<=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_SHL(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHL(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -765,9 +752,9 @@
      * Binary enter - callback for entering {@literal >>>=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_SHR(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SHR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -785,9 +772,9 @@
      * Binary enter - callback for entering -= operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterASSIGN_SUB(final BinaryNode binaryNode) {
+    public boolean enterASSIGN_SUB(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -805,9 +792,9 @@
      * Binary enter - callback for entering a bind operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBIND(final BinaryNode binaryNode) {
+    public boolean enterBIND(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -825,9 +812,9 @@
      * Binary enter - callback for entering {@literal &} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBIT_AND(final BinaryNode binaryNode) {
+    public boolean enterBIT_AND(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -845,9 +832,9 @@
      * Binary enter - callback for entering | operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBIT_OR(final BinaryNode binaryNode) {
+    public boolean enterBIT_OR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -865,9 +852,9 @@
      * Binary enter - callback for entering ^ operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBIT_XOR(final BinaryNode binaryNode) {
+    public boolean enterBIT_XOR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -886,9 +873,9 @@
      * (a, b) where the result is a
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCOMMALEFT(final BinaryNode binaryNode) {
+    public boolean enterCOMMALEFT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -908,9 +895,9 @@
      * (a, b) where the result is b
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCOMMARIGHT(final BinaryNode binaryNode) {
+    public boolean enterCOMMARIGHT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -929,9 +916,9 @@
      * Binary enter - callback for entering a division
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterDIV(final BinaryNode binaryNode) {
+    public boolean enterDIV(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -949,9 +936,9 @@
      * Binary enter - callback for entering == operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterEQ(final BinaryNode binaryNode) {
+    public boolean enterEQ(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -969,9 +956,9 @@
      * Binary enter - callback for entering === operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterEQ_STRICT(final BinaryNode binaryNode) {
+    public boolean enterEQ_STRICT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -989,9 +976,9 @@
      * Binary enter - callback for entering {@literal >=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterGE(final BinaryNode binaryNode) {
+    public boolean enterGE(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1009,9 +996,9 @@
      * Binary enter - callback for entering {@literal >} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterGT(final BinaryNode binaryNode) {
+    public boolean enterGT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1029,9 +1016,9 @@
      * Binary enter - callback for entering in operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterIN(final BinaryNode binaryNode) {
+    public boolean enterIN(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1049,9 +1036,9 @@
      * Binary enter - callback for entering instanceof operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterINSTANCEOF(final BinaryNode binaryNode) {
+    public boolean enterINSTANCEOF(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1069,9 +1056,9 @@
      * Binary enter - callback for entering {@literal <=} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterLE(final BinaryNode binaryNode) {
+    public boolean enterLE(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1089,9 +1076,9 @@
      * Binary enter - callback for entering {@literal <} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterLT(final BinaryNode binaryNode) {
+    public boolean enterLT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1108,9 +1095,9 @@
      * Binary enter - callback for entering % operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterMOD(final BinaryNode binaryNode) {
+    public boolean enterMOD(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1128,9 +1115,9 @@
      * Binary enter - callback for entering * operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterMUL(final BinaryNode binaryNode) {
+    public boolean enterMUL(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1148,9 +1135,9 @@
      * Binary enter - callback for entering != operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterNE(final BinaryNode binaryNode) {
+    public boolean enterNE(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1168,9 +1155,9 @@
      * Binary enter - callback for entering a !== operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterNE_STRICT(final BinaryNode binaryNode) {
+    public boolean enterNE_STRICT(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1188,9 +1175,9 @@
      * Binary enter - callback for entering || operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterOR(final BinaryNode binaryNode) {
+    public boolean enterOR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1208,9 +1195,9 @@
      * Binary enter - callback for entering {@literal >>} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSAR(final BinaryNode binaryNode) {
+    public boolean enterSAR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1228,9 +1215,9 @@
      * Binary enter - callback for entering {@literal <<} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSHL(final BinaryNode binaryNode) {
+    public boolean enterSHL(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1247,9 +1234,9 @@
      * Binary enter - callback for entering {@literal >>>} operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSHR(final BinaryNode binaryNode) {
+    public boolean enterSHR(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -1267,9 +1254,9 @@
      * Binary enter - callback for entering - operator
      *
      * @param  binaryNode the node
-     * @return processed node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSUB(final BinaryNode binaryNode) {
+    public boolean enterSUB(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Thu May 16 11:47:51 2013 +0100
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.internal.ir.visitor;
 
-import jdk.nashorn.internal.codegen.CompileUnit;
-import jdk.nashorn.internal.codegen.MethodEmitter;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
@@ -35,7 +33,6 @@
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -44,6 +41,7 @@
 import jdk.nashorn.internal.ir.IfNode;
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.Node;
@@ -65,41 +63,30 @@
  * Visitor used to navigate the IR.
  */
 public abstract class NodeVisitor {
-    /** Current functionNode. */
-    private FunctionNode currentFunctionNode;
-
-    /** Current compile unit used for class generation. */
-    private CompileUnit compileUnit;
+    private final LexicalContext lc;
 
     /**
-     * Current method visitor used for method generation.
-     * <p>
-     * TODO: protected is just for convenience and readability, so that
-     * subclasses can directly use 'method' - might want to change that
-     */
-    protected MethodEmitter method;
-
-    /** Current block. */
-    private Block currentBlock;
-
-    /**
-     * Constructor.
+     * Constructor
      */
     public NodeVisitor() {
-        this(null, null);
+        this(new LexicalContext());
     }
 
     /**
      * Constructor
      *
-     * @param compileUnit compile unit for this node visitor
-     * @param method method emitter for this node visitor
+     * @param lc a custom lexical context
      */
-    public NodeVisitor(final CompileUnit compileUnit, final MethodEmitter method) {
-        super();
+    public NodeVisitor(final LexicalContext lc) {
+        this.lc = lc;
+    }
 
-        this.compileUnit = compileUnit;
-        this.method      = method;
+    /**
+     * Get the lexical context of this node visitor
+     * @return lexical context
+     */
+    public LexicalContext getLexicalContext() {
+        return lc;
     }
 
     /**
@@ -118,10 +105,10 @@
      *
      * @see NodeVisitor#leaveDefault(Node)
      * @param node the node to visit
-     * @return the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    protected Node enterDefault(final Node node) {
-        return node;
+    protected boolean enterDefault(final Node node) {
+        return true;
     }
 
     /**
@@ -150,9 +137,9 @@
      * Callback for entering an AccessNode
      *
      * @param  accessNode the node
-     * @return processed node, null if traversal should end, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterAccessNode(final AccessNode accessNode) {
+    public boolean enterAccessNode(final AccessNode accessNode) {
         return enterDefault(accessNode);
     }
 
@@ -170,9 +157,9 @@
      * Callback for entering a Block
      *
      * @param  block     the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBlock(final Block block) {
+    public boolean enterBlock(final Block block) {
         return enterDefault(block);
     }
 
@@ -192,7 +179,7 @@
      * @param  binaryNode  the node
      * @return processed   node
      */
-    public Node enterBinaryNode(final BinaryNode binaryNode) {
+    public boolean enterBinaryNode(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
@@ -210,9 +197,9 @@
      * Callback for entering a BreakNode
      *
      * @param  breakNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterBreakNode(final BreakNode breakNode) {
+    public boolean enterBreakNode(final BreakNode breakNode) {
         return enterDefault(breakNode);
     }
 
@@ -230,9 +217,9 @@
      * Callback for entering a CallNode
      *
      * @param  callNode  the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCallNode(final CallNode callNode) {
+    public boolean enterCallNode(final CallNode callNode) {
         return enterDefault(callNode);
     }
 
@@ -250,9 +237,9 @@
      * Callback for entering a CaseNode
      *
      * @param  caseNode  the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCaseNode(final CaseNode caseNode) {
+    public boolean enterCaseNode(final CaseNode caseNode) {
         return enterDefault(caseNode);
     }
 
@@ -270,9 +257,9 @@
      * Callback for entering a CatchNode
      *
      * @param  catchNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterCatchNode(final CatchNode catchNode) {
+    public boolean enterCatchNode(final CatchNode catchNode) {
         return enterDefault(catchNode);
     }
 
@@ -290,9 +277,9 @@
      * Callback for entering a ContinueNode
      *
      * @param  continueNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterContinueNode(final ContinueNode continueNode) {
+    public boolean enterContinueNode(final ContinueNode continueNode) {
         return enterDefault(continueNode);
     }
 
@@ -307,32 +294,12 @@
     }
 
     /**
-     * Callback for entering a DoWhileNode
-     *
-     * @param  doWhileNode the node
-     * @return processed   node
-     */
-    public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
-        return enterDefault(doWhileNode);
-    }
-
-    /**
-     * Callback for leaving a DoWhileNode
-     *
-     * @param  doWhileNode the node
-     * @return processed node, which will replace the original one, or the original node
-     */
-    public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
-        return leaveDefault(doWhileNode);
-    }
-
-    /**
      * Callback for entering an EmptyNode
      *
      * @param  emptyNode   the node
-     * @return processed   node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterEmptyNode(final EmptyNode emptyNode) {
+    public boolean enterEmptyNode(final EmptyNode emptyNode) {
         return enterDefault(emptyNode);
     }
 
@@ -350,9 +317,9 @@
      * Callback for entering an ExecuteNode
      *
      * @param  executeNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterExecuteNode(final ExecuteNode executeNode) {
+    public boolean enterExecuteNode(final ExecuteNode executeNode) {
         return enterDefault(executeNode);
     }
 
@@ -370,9 +337,9 @@
      * Callback for entering a ForNode
      *
      * @param  forNode   the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterForNode(final ForNode forNode) {
+    public boolean enterForNode(final ForNode forNode) {
         return enterDefault(forNode);
     }
 
@@ -390,9 +357,9 @@
      * Callback for entering a FunctionNode
      *
      * @param  functionNode the node
-     * @return processed    node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterFunctionNode(final FunctionNode functionNode) {
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
         return enterDefault(functionNode);
     }
 
@@ -410,9 +377,9 @@
      * Callback for entering an IdentNode
      *
      * @param  identNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterIdentNode(final IdentNode identNode) {
+    public boolean enterIdentNode(final IdentNode identNode) {
         return enterDefault(identNode);
     }
 
@@ -429,10 +396,10 @@
     /**
      * Callback for entering an IfNode
      *
-     * @param  ifNode    the node
-     * @return processed node, null if traversal should end
+     * @param  ifNode the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterIfNode(final IfNode ifNode) {
+    public boolean enterIfNode(final IfNode ifNode) {
         return enterDefault(ifNode);
     }
 
@@ -450,9 +417,9 @@
      * Callback for entering an IndexNode
      *
      * @param  indexNode  the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterIndexNode(final IndexNode indexNode) {
+    public boolean enterIndexNode(final IndexNode indexNode) {
         return enterDefault(indexNode);
     }
 
@@ -470,9 +437,9 @@
      * Callback for entering a LabelNode
      *
      * @param  labelNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterLabelNode(final LabelNode labelNode) {
+    public boolean enterLabelNode(final LabelNode labelNode) {
         return enterDefault(labelNode);
     }
 
@@ -490,9 +457,9 @@
      * Callback for entering a LineNumberNode
      *
      * @param  lineNumberNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
+    public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) {
         return enterDefault(lineNumberNode);
     }
 
@@ -510,9 +477,9 @@
      * Callback for entering a LiteralNode
      *
      * @param  literalNode the node
-     * @return processed   node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterLiteralNode(final LiteralNode<?> literalNode) {
+    public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
         return enterDefault(literalNode);
     }
 
@@ -530,9 +497,9 @@
      * Callback for entering an ObjectNode
      *
      * @param  objectNode the node
-     * @return processed  node
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterObjectNode(final ObjectNode objectNode) {
+    public boolean enterObjectNode(final ObjectNode objectNode) {
         return enterDefault(objectNode);
     }
 
@@ -550,9 +517,9 @@
      * Callback for entering a PropertyNode
      *
      * @param  propertyNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterPropertyNode(final PropertyNode propertyNode) {
+    public boolean enterPropertyNode(final PropertyNode propertyNode) {
         return enterDefault(propertyNode);
     }
 
@@ -570,9 +537,9 @@
      * Callback for entering a ReturnNode
      *
      * @param  returnNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterReturnNode(final ReturnNode returnNode) {
+    public boolean enterReturnNode(final ReturnNode returnNode) {
         return enterDefault(returnNode);
     }
 
@@ -590,9 +557,9 @@
      * Callback for entering a RuntimeNode
      *
      * @param  runtimeNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
+    public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
         return enterDefault(runtimeNode);
     }
 
@@ -610,9 +577,9 @@
      * Callback for entering a SplitNode
      *
      * @param  splitNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSplitNode(final SplitNode splitNode) {
+    public boolean enterSplitNode(final SplitNode splitNode) {
         return enterDefault(splitNode);
     }
 
@@ -630,9 +597,9 @@
      * Callback for entering a SwitchNode
      *
      * @param  switchNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterSwitchNode(final SwitchNode switchNode) {
+    public boolean enterSwitchNode(final SwitchNode switchNode) {
         return enterDefault(switchNode);
     }
 
@@ -650,9 +617,9 @@
      * Callback for entering a TernaryNode
      *
      * @param  ternaryNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterTernaryNode(final TernaryNode ternaryNode) {
+    public boolean enterTernaryNode(final TernaryNode ternaryNode) {
         return enterDefault(ternaryNode);
     }
 
@@ -670,9 +637,9 @@
      * Callback for entering a ThrowNode
      *
      * @param  throwNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterThrowNode(final ThrowNode throwNode) {
+    public boolean enterThrowNode(final ThrowNode throwNode) {
         return enterDefault(throwNode);
     }
 
@@ -690,9 +657,9 @@
      * Callback for entering a TryNode
      *
      * @param  tryNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterTryNode(final TryNode tryNode) {
+    public boolean enterTryNode(final TryNode tryNode) {
         return enterDefault(tryNode);
     }
 
@@ -710,9 +677,9 @@
      * Callback for entering a UnaryNode
      *
      * @param  unaryNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterUnaryNode(final UnaryNode unaryNode) {
+    public boolean enterUnaryNode(final UnaryNode unaryNode) {
         return enterDefault(unaryNode);
     }
 
@@ -730,9 +697,9 @@
      * Callback for entering a VarNode
      *
      * @param  varNode   the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterVarNode(final VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         return enterDefault(varNode);
     }
 
@@ -750,9 +717,9 @@
      * Callback for entering a WhileNode
      *
      * @param  whileNode the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterWhileNode(final WhileNode whileNode) {
+    public boolean enterWhileNode(final WhileNode whileNode) {
         return enterDefault(whileNode);
     }
 
@@ -770,9 +737,9 @@
      * Callback for entering a WithNode
      *
      * @param  withNode  the node
-     * @return processed node, null if traversal should end
+     * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public Node enterWithNode(final WithNode withNode) {
+    public boolean enterWithNode(final WithNode withNode) {
         return enterDefault(withNode);
     }
 
@@ -786,74 +753,5 @@
         return leaveDefault(withNode);
     }
 
-    /**
-     * Get the current function node for this NodeVisitor
-     * @see FunctionNode
-     * @return the function node being visited
-     */
-    public FunctionNode getCurrentFunctionNode() {
-        return currentFunctionNode;
-    }
-
-    /**
-     * Reset the current function node being visited for this NodeVisitor
-     * @see FunctionNode
-     * @param currentFunctionNode a new function node to traverse
-     */
-    public void setCurrentFunctionNode(final FunctionNode currentFunctionNode) {
-        this.currentFunctionNode = currentFunctionNode;
-    }
-
-    /**
-     * Get the current compile unit for this NodeVisitor
-     * @see CompileUnit
-     * @return a compile unit, or null if not a compiling NodeVisitor
-     */
-    public CompileUnit getCurrentCompileUnit() {
-        return compileUnit;
-    }
-
-    /**
-     * Set the current compile unit for this NodeVisitor
-     * @see CompileUnit
-     * @param compileUnit a new compile unit
-     */
-    public void setCurrentCompileUnit(final CompileUnit compileUnit) {
-        this.compileUnit = compileUnit;
-    }
-
-    /**
-     * Get the current method emitter for this NodeVisitor
-     * @see MethodEmitter
-     * @return the method emitter
-     */
-    public MethodEmitter getCurrentMethodEmitter() {
-        return method;
-    }
-
-    /**
-     * Reset the current method emitter for this NodeVisitor
-     * @see MethodEmitter
-     * @param method a new method emitter
-     */
-    public void setCurrentMethodEmitter(final MethodEmitter method) {
-        this.method = method;
-    }
-
-    /**
-     * Get the current Block being traversed for this NodeVisitor
-     * @return the current block
-     */
-    public Block getCurrentBlock() {
-        return currentBlock;
-    }
-
-    /**
-     * Reset the Block to be traversed for this NodeVisitor
-     * @param currentBlock the new current block
-     */
-    public void setCurrentBlock(final Block currentBlock) {
-        this.currentBlock = currentBlock;
-    }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Thu May 16 11:47:51 2013 +0100
@@ -137,7 +137,7 @@
      */
     static Object traceReturn(final DebugLogger logger, final Object value) {
         final String str = "\treturn: " + stripName(value) + " [type=" + (value == null ? "null" : stripName(value.getClass()) + ']');
-        logger.log(str, TRACE_LEVEL);
+        logger.log(TRACE_LEVEL, str);
         return value;
     }
 
@@ -173,7 +173,7 @@
         }
 
         assert logger != null;
-        logger.log(sb.toString(), TRACE_LEVEL);
+        logger.log(TRACE_LEVEL, sb);
         stacktrace(logger);
     }
 
@@ -184,7 +184,7 @@
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         final PrintStream ps = new PrintStream(baos);
         new Throwable().printStackTrace(ps);
-        logger.log(baos.toString(), TRACE_LEVEL);
+        logger.log(TRACE_LEVEL, baos.toString());
     }
 
     private static String argString(final Object arg) {
@@ -614,7 +614,7 @@
         @Override
         public SwitchPoint createSwitchPoint() {
             final SwitchPoint sp = super.createSwitchPoint();
-            LOG.log("createSwitchPoint " + sp, TRACE_LEVEL);
+            LOG.log(TRACE_LEVEL, "createSwitchPoint ", sp);
             return sp;
         }
 
@@ -627,7 +627,7 @@
         @Override
         public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) {
             final MethodType mt = super.type(returnType, paramTypes);
-            LOG.log("methodType " + returnType + ' ' + Arrays.toString(paramTypes) + ' ' + mt, TRACE_LEVEL);
+            LOG.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt);
             return mt;
         }
     }
@@ -638,7 +638,7 @@
     private static class TraceCreateMethodHandleFunctionality extends TraceMethodHandleFunctionality {
         @Override
         public MethodHandle debug(final MethodHandle master, final String str, final Object... args) {
-            LOG.log(str + ' ' + describe(args), TRACE_LEVEL);
+            LOG.log(TRACE_LEVEL, str, " ", describe(args));
             stacktrace(LOG);
             return master;
         }
--- a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -40,7 +40,7 @@
 
     BoundScriptFunctionImpl(ScriptFunctionData data, ScriptFunction targetFunction) {
         super(data);
-        this.prototype = ScriptRuntime.UNDEFINED;
+        setPrototype(ScriptRuntime.UNDEFINED);
         this.targetFunction = targetFunction;
     }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java	Thu May 16 11:47:51 2013 +0100
@@ -418,7 +418,7 @@
                 long length;
                 if (len instanceof Integer || len instanceof Long) {
                     length = ((Number) len).longValue();
-                    if (length >= 0 && length < 0xffff_ffffL) {
+                    if (length >= 0 && length < JSType.MAX_UINT) {
                         return new NativeArray(length);
                     }
                 }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java	Thu May 16 11:47:51 2013 +0100
@@ -182,7 +182,8 @@
 
     @Override
     public String safeToString() {
-        return "[Date " + toISOStringImpl(this) + "]";
+        final String str = isValidDate() ? toISOStringImpl(this) : INVALID_DATE;
+        return "[Date " + str + "]";
     }
 
     @Override
@@ -518,7 +519,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object getTimezoneOffset(final Object self) {
         final NativeDate nd = getNativeDate(self);
-        if (nd != null) {
+        if (nd != null && nd.isValidDate()) {
             final long msec = (long) nd.getTime();
             return - nd.getTimeZone().getOffset(msec) / msPerMinute;
         }
@@ -534,8 +535,8 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object setTime(final Object self, final Object time) {
+        final NativeDate nd  = getNativeDate(self);
         final double     num = timeClip(JSType.toNumber(time));
-        final NativeDate nd  = getNativeDate(self);
         nd.setTime(num);
         return num;
     }
@@ -550,9 +551,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static Object setMilliseconds(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MILLISECOND, args, true);
-        }
+        setFields(nd, MILLISECOND, args, true);
         return nd.getTime();
     }
 
@@ -566,9 +565,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static Object setUTCMilliseconds(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MILLISECOND, args, false);
-        }
+        setFields(nd, MILLISECOND, args, false);
         return nd.getTime();
     }
 
@@ -582,9 +579,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
     public static Object setSeconds(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, SECOND, args, true);
-        }
+        setFields(nd, SECOND, args, true);
         return nd.getTime();
     }
 
@@ -598,9 +593,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
     public static Object setUTCSeconds(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, SECOND, args, false);
-        }
+        setFields(nd, SECOND, args, false);
         return nd.getTime();
     }
 
@@ -614,9 +607,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
     public static Object setMinutes(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MINUTE, args, true);
-        }
+        setFields(nd, MINUTE, args, true);
         return nd.getTime();
     }
 
@@ -630,9 +621,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 3)
     public static Object setUTCMinutes(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MINUTE, args, false);
-        }
+        setFields(nd, MINUTE, args, false);
         return nd.getTime();
     }
 
@@ -646,9 +635,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
     public static Object setHours(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, HOUR, args, true);
-        }
+        setFields(nd, HOUR, args, true);
         return nd.getTime();
     }
 
@@ -662,9 +649,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 4)
     public static Object setUTCHours(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, HOUR, args, false);
-        }
+        setFields(nd, HOUR, args, false);
         return nd.getTime();
     }
 
@@ -678,9 +663,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static Object setDate(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, DAY, args, true);
-        }
+        setFields(nd, DAY, args, true);
         return nd.getTime();
     }
 
@@ -694,9 +677,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
     public static Object setUTCDate(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, DAY, args, false);
-        }
+        setFields(nd, DAY, args, false);
         return nd.getTime();
     }
 
@@ -710,9 +691,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
     public static Object setMonth(final Object self, final Object... args) {
         final NativeDate nd = getNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MONTH, args, true);
-        }
+        setFields(nd, MONTH, args, true);
         return nd.getTime();
     }
 
@@ -726,9 +705,7 @@
     @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 2)
     public static Object setUTCMonth(final Object self, final Object... args) {
         final NativeDate nd = ensureNativeDate(self);
-        if (nd.isValidDate()) {
-            setFields(nd, MONTH, args, false);
-        }
+        setFields(nd, MONTH, args, false);
         return nd.getTime();
     }
 
@@ -746,7 +723,11 @@
             setFields(nd, YEAR, args, true);
         } else {
             final double[] d = convertArgs(args, 0, YEAR, YEAR, 3);
-            nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone())));
+            if (d != null) {
+                nd.setTime(timeClip(utc(makeDate(makeDay(d[0], d[1], d[2]), 0), nd.getTimeZone())));
+            } else {
+                nd.setTime(NaN);
+            }
         }
         return nd.getTime();
     }
@@ -781,13 +762,13 @@
     public static Object setYear(final Object self, final Object year) {
         final NativeDate nd = getNativeDate(self);
         if (isNaN(nd.getTime())) {
-            return null;
+            nd.setTime(utc(0, nd.getTimeZone()));
         }
 
         final double yearNum = JSType.toNumber(year);
         if (isNaN(yearNum)) {
             nd.setTime(NaN);
-            return nd;
+            return nd.getTime();
         }
         int yearInt = JSType.toInteger(yearNum);
         if (0 <= yearInt && yearInt <= 99) {
@@ -795,7 +776,7 @@
         }
         setFields(nd, YEAR, new Object[] {yearInt}, true);
 
-        return nd;
+        return nd.getTime();
     }
 
     /**
@@ -851,11 +832,11 @@
         }
         final ScriptObject sobj  = (ScriptObject)selfObj;
         final Object       value = sobj.getDefaultValue(Number.class);
-
-        final double num = (value instanceof Number) ? ((Number)value).doubleValue() : NaN;
-
-        if (isInfinite(num) || isNaN(num)) {
-            return null;
+        if (value instanceof Number) {
+            final double num = ((Number)value).doubleValue();
+            if (isInfinite(num) || isNaN(num)) {
+                return null;
+            }
         }
 
         try {
@@ -1297,6 +1278,10 @@
         final double time = local ? nd.getLocalTime() : nd.getTime();
         final double d[] = convertArgs(args, time, fieldId, start, length);
 
+        if (! nd.isValidDate()) {
+            return;
+        }
+
         double newTime;
         if (d == null) {
             newTime = NaN;
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java	Thu May 16 11:47:51 2013 +0100
@@ -247,7 +247,6 @@
         out.println("Scope count " + ScriptObject.getScopeCount());
         out.println("ScriptObject listeners added " + PropertyListenerManager.getListenersAdded());
         out.println("ScriptObject listeners removed " + PropertyListenerManager.getListenersRemoved());
-        out.println("ScriptObject listeners dead " + PropertyListenerManager.getListenersDead());
         out.println("ScriptFunction count " + ScriptObject.getCount());
         out.println("ScriptFunction invokes " + ScriptFunction.getInvokes());
         out.println("ScriptFunction allocations " + ScriptFunction.getAllocations());
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java	Thu May 16 11:47:51 2013 +0100
@@ -81,23 +81,13 @@
 
         Object[] args = null;
 
-        if (ScriptObject.isArray(array)) {
-            args = ((NativeArray)array).asObjectArray();
-        } else if (array instanceof ScriptObject) {
+        if (array instanceof ScriptObject) {
             // look for array-like object
             final ScriptObject sobj = (ScriptObject)array;
             final Object       len  = sobj.getLength();
-
-            if (len == UNDEFINED || len == null) {
-                throw typeError("function.apply.expects.array");
-            }
+            final int n = (int)JSType.toUint32(len);
 
-            final int n = (int)JSType.toUint32(len);
-            if (n != JSType.toNumber(len)) {
-                throw typeError("function.apply.expects.array");
-            }
-
-            args = new Object[(int)JSType.toUint32(len)];
+            args = new Object[n];
             for (int i = 0; i < args.length; i++) {
                 args[i] = sobj.get(i);
             }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Thu May 16 11:47:51 2013 +0100
@@ -148,11 +148,7 @@
         if (overrides instanceof ScriptObject) {
             this.overrides = true;
             final ScriptObject sobj = (ScriptObject)overrides;
-            final Iterator<String> iter = sobj.propertyIterator();
-            while (iter.hasNext()) {
-                final String prop = iter.next();
-                super.set(prop, sobj.get(prop), false);
-            }
+            this.addBoundProperties(sobj);
         } else {
             this.overrides = false;
         }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java	Thu May 16 11:47:51 2013 +0100
@@ -229,7 +229,7 @@
         final JSType type = JSType.of(value);
         if (type == JSType.OBJECT) {
             if (isArray(value)) {
-                return JA((NativeArray)value, state);
+                return JA((ScriptObject)value, state);
             } else if (value instanceof ScriptObject) {
                 return JO((ScriptObject)value, state);
             }
@@ -315,7 +315,7 @@
     }
 
     // Spec: The abstract operation JA(value) serializes an array.
-    private static Object JA(final NativeArray value, final StringifyState state) {
+    private static Object JA(final ScriptObject value, final StringifyState state) {
         if (state.stack.containsKey(value)) {
             throw typeError("JSON.stringify.cyclic");
         }
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java	Thu May 16 11:47:51 2013 +0100
@@ -523,23 +523,28 @@
     }
 
     private RegExpResult execInner(final String string) {
+        final boolean isGlobal = regexp.isGlobal();
         int start = getLastIndex();
-        if (! regexp.isGlobal()) {
+        if (!isGlobal) {
             start = 0;
         }
 
         if (start < 0 || start > string.length()) {
-            setLastIndex(0);
+            if (isGlobal) {
+                setLastIndex(0);
+            }
             return null;
         }
 
         final RegExpMatcher matcher = regexp.match(string);
         if (matcher == null || !matcher.search(start)) {
-            setLastIndex(0);
+            if (isGlobal) {
+                setLastIndex(0);
+            }
             return null;
         }
 
-        if (regexp.isGlobal()) {
+        if (isGlobal) {
             setLastIndex(matcher.end());
         }
 
@@ -548,6 +553,22 @@
         return match;
     }
 
+    // String.prototype.split method ignores the global flag and should not update lastIndex property.
+    private RegExpResult execSplit(final String string, int start) {
+        if (start < 0 || start > string.length()) {
+            return null;
+        }
+
+        final RegExpMatcher matcher = regexp.match(string);
+        if (matcher == null || !matcher.search(start)) {
+            return null;
+        }
+
+        final RegExpResult match = new RegExpResult(string, matcher.start(), groups(matcher));
+        globalObject.setLastRegExpResult(match);
+        return match;
+    }
+
     /**
      * Convert java.util.regex.Matcher groups to JavaScript groups.
      * That is, replace null and groups that didn't match with undefined.
@@ -600,7 +621,7 @@
      * @return True if a match is found.
      */
     public Object test(final String string) {
-        return exec(string) != null;
+        return execInner(string) != null;
     }
 
     /**
@@ -765,35 +786,31 @@
      * @return Array of substrings.
      */
     Object split(final String string, final long limit) {
-        return split(this, string, limit);
-    }
-
-    private static Object split(final NativeRegExp regexp0, final String input, final long limit) {
-        final List<Object> matches = new ArrayList<>();
-
-        final NativeRegExp regexp = new NativeRegExp(regexp0);
-        regexp.setGlobal(true);
-
         if (limit == 0L) {
             return new NativeArray();
         }
 
+        final List<Object> matches = new ArrayList<>();
+
         RegExpResult match;
-        final int inputLength = input.length();
+        final int inputLength = string.length();
         int lastLength = -1;
+        int lastIndex = 0;
         int lastLastIndex = 0;
 
-        while ((match = regexp.execInner(input)) != null) {
-            final int lastIndex = match.getIndex() + match.length();
+        while ((match = execSplit(string, lastIndex)) != null) {
+            lastIndex = match.getIndex() + match.length();
 
             if (lastIndex > lastLastIndex) {
-                matches.add(input.substring(lastLastIndex, match.getIndex()));
-                if (match.getGroups().length > 1 && match.getIndex() < inputLength) {
-                    matches.addAll(Arrays.asList(match.getGroups()).subList(1, match.getGroups().length));
+                matches.add(string.substring(lastLastIndex, match.getIndex()));
+                final Object[] groups = match.getGroups();
+                if (groups.length > 1 && match.getIndex() < inputLength) {
+                    for (int index = 1; index < groups.length && matches.size() < limit; index++) {
+                        matches.add(groups[index]);
+                    }
                 }
 
                 lastLength = match.length();
-                lastLastIndex = lastIndex;
 
                 if (matches.size() >= limit) {
                     break;
@@ -801,8 +818,10 @@
             }
 
             // bump the index to avoid infinite loop
-            if (regexp.getLastIndex() == match.getIndex()) {
-                regexp.setLastIndex(match.getIndex() + 1);
+            if (lastIndex == lastLastIndex) {
+                lastIndex++;
+            } else {
+                lastLastIndex = lastIndex;
             }
         }
 
@@ -810,12 +829,12 @@
             // check special case if we need to append an empty string at the
             // end of the match
             // if the lastIndex was the entire string
-            if (lastLastIndex == input.length()) {
-                if (lastLength > 0 || regexp.test("") == Boolean.FALSE) {
+            if (lastLastIndex == string.length()) {
+                if (lastLength > 0 || execSplit("", 0) == null) {
                     matches.add("");
                 }
             } else {
-                matches.add(input.substring(lastLastIndex, inputLength));
+                matches.add(string.substring(lastLastIndex, inputLength));
             }
         }
 
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java	Thu May 16 11:47:51 2013 +0100
@@ -51,6 +51,7 @@
 
     NativeRegExpExecResult(final RegExpResult result) {
         setProto(Global.instance().getArrayPrototype());
+        setIsArray();
         this.setArray(ArrayData.allocate(result.getGroups().clone()));
         this.index = result.getIndex();
         this.input = result.getInput();
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java	Thu May 16 11:47:51 2013 +0100
@@ -25,11 +25,11 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -41,6 +41,7 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
@@ -55,7 +56,6 @@
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
 
@@ -179,7 +179,6 @@
         return ((ScriptObject) Global.toObject(self)).get(key);
     }
 
-    @SuppressWarnings("unused")
     private static Object get(final Object self, final int key) {
         final CharSequence cs = JSType.toCharSequence(self);
         if (key >= 0 && key < cs.length()) {
@@ -842,7 +841,7 @@
         final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit);
 
         if (separator == UNDEFINED) {
-            return new NativeArray(new Object[]{str});
+            return lim == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
         }
 
         if (separator instanceof NativeRegExp) {
@@ -855,8 +854,9 @@
 
     private static Object splitString(String str, String separator, long limit) {
         if (separator.isEmpty()) {
-            final Object[] array = new Object[str.length()];
-            for (int i = 0; i < array.length; i++) {
+            final int length = (int) Math.min(str.length(), limit);
+            final Object[] array = new Object[length];
+            for (int i = 0; i < length; i++) {
                 array[i] = String.valueOf(str.charAt(i));
             }
             return new NativeArray(array);
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java	Thu May 16 11:47:51 2013 +0100
@@ -29,6 +29,7 @@
 import jdk.nashorn.internal.objects.annotations.Constructor;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayData;
 
@@ -71,17 +72,17 @@
 
         @Override
         protected long getLongImpl(final int key) {
-            return getIntImpl(key) & 0xffff_ffffL;
+            return getIntImpl(key) & JSType.MAX_UINT;
         }
 
         @Override
         protected double getDoubleImpl(final int key) {
-            return getIntImpl(key) & 0xffff_ffffL;
+            return getIntImpl(key) & JSType.MAX_UINT;
         }
 
         @Override
         protected Object getObjectImpl(final int key) {
-            return getIntImpl(key) & 0xffff_ffffL;
+            return getIntImpl(key) & JSType.MAX_UINT;
         }
 
         @Override
--- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Thu May 16 11:47:51 2013 +0100
@@ -42,6 +42,10 @@
  * function objects -- to expose properties like "prototype", "length" etc.
  */
 public class ScriptFunctionImpl extends ScriptFunction {
+
+    /** Reference to constructor prototype. */
+    private Object prototype;
+
     // property map for strict mode functions
     private static final PropertyMap strictmodemap$;
     // property map for bound functions
@@ -49,6 +53,9 @@
     // property map for non-strict, non-bound functions.
     private static final PropertyMap nasgenmap$;
 
+    // Marker object for lazily initialized prototype object
+    private static final Object LAZY_PROTOTYPE = new Object();
+
     /**
      * Constructor called by Nasgen generated code, no membercount, use the default map.
      * Creates builtin functions only.
@@ -83,8 +90,8 @@
      * @param methodHandle handle for invocation
      * @param scope scope object
      * @param specs specialized versions of this method, if available, null otherwise
-     * @param strict are we in strict mode
-     * @param builtin is this a built-in function
+     * @param 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).
      */
     ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
@@ -235,10 +242,23 @@
         return Global.objectPrototype();
     }
 
+    @Override
+    public final Object getPrototype() {
+        if (prototype == LAZY_PROTOTYPE) {
+            prototype = new PrototypeObject(this);
+        }
+        return prototype;
+    }
+
+    @Override
+    public final void setPrototype(final Object prototype) {
+        this.prototype = prototype;
+    }
+
     // Internals below..
     private void init() {
         this.setProto(Global.instance().getFunctionPrototype());
-        this.setPrototype(new PrototypeObject(this));
+        this.prototype = LAZY_PROTOTYPE;
 
         if (isStrict()) {
             final ScriptFunction func = getTypeErrorThrower();
--- a/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/AbstractParser.java	Thu May 16 11:47:51 2013 +0100
@@ -37,8 +37,8 @@
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
 import jdk.nashorn.internal.runtime.ParserException;
+import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.regexp.RegExpFactory;
-import jdk.nashorn.internal.runtime.Source;
 
 /**
  * Base class for parsers.
@@ -197,9 +197,10 @@
      *
      * @param message    Error message.
      * @param errorToken Offending token.
+     * @return ParserException upon failure. Caller should throw and not ignore
      */
-    protected final void error(final String message, final long errorToken) {
-        error(JSErrorType.SYNTAX_ERROR, message, errorToken);
+    protected final ParserException error(final String message, final long errorToken) {
+        return error(JSErrorType.SYNTAX_ERROR, message, errorToken);
     }
 
     /**
@@ -208,22 +209,24 @@
      * @param errorType  The error type
      * @param message    Error message.
      * @param errorToken Offending token.
+     * @return ParserException upon failure. Caller should throw and not ignore
      */
-    protected final void error(final JSErrorType errorType, final String message, final long errorToken) {
+    protected final ParserException error(final JSErrorType errorType, final String message, final long errorToken) {
         final int position  = Token.descPosition(errorToken);
         final int lineNum   = source.getLine(position);
         final int columnNum = source.getColumn(position);
         final String formatted = ErrorManager.format(message, source, lineNum, columnNum, errorToken);
-        throw new ParserException(errorType, formatted, source, lineNum, columnNum, errorToken);
+        return new ParserException(errorType, formatted, source, lineNum, columnNum, errorToken);
     }
 
     /**
      * Report an error.
      *
      * @param message Error message.
+     * @return ParserException upon failure. Caller should throw and not ignore
      */
-    protected final void error(final String message) {
-        error(JSErrorType.SYNTAX_ERROR, message);
+    protected final ParserException error(final String message) {
+        return error(JSErrorType.SYNTAX_ERROR, message);
     }
 
     /**
@@ -231,13 +234,24 @@
      *
      * @param errorType  The error type
      * @param message    Error message.
+     * @return ParserException upon failure. Caller should throw and not ignore
      */
-    protected final void error(final JSErrorType errorType, final String message) {
+    protected final ParserException error(final JSErrorType errorType, final String message) {
         // TODO - column needs to account for tabs.
         final int position = Token.descPosition(token);
         final int column = position - linePosition;
         final String formatted = ErrorManager.format(message, source, line, column, token);
-        throw new ParserException(errorType, formatted, source, line, column, token);
+        return new ParserException(errorType, formatted, source, line, column, token);
+    }
+
+    /**
+     * Report a warning to the error manager.
+     *
+     * @param errorType  The error type of the warning
+     * @param message    Warning message.
+     */
+    protected final void warning(final JSErrorType errorType, final String message, final long errorToken) {
+        errors.warning(error(errorType, message, errorToken));
     }
 
     /**
@@ -270,7 +284,7 @@
      */
     protected final void expect(final TokenType expected) throws ParserException {
         if (type != expected) {
-            error(expectMessage(expected));
+            throw error(expectMessage(expected));
         }
 
         next();
@@ -285,7 +299,7 @@
      */
     protected final Object expectValue(final TokenType expected) throws ParserException {
         if (type != expected) {
-            error(expectMessage(expected));
+            throw error(expectMessage(expected));
         }
 
         final Object value = getValue();
@@ -429,7 +443,7 @@
                 try {
                     RegExpFactory.validate(regex.getExpression(), regex.getOptions());
                 } catch (final ParserException e) {
-                    error(e.getMessage());
+                    throw error(e.getMessage());
                 }
             }
             node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value);
--- a/nashorn/src/jdk/nashorn/internal/parser/JSONParser.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/JSONParser.java	Thu May 16 11:47:51 2013 +0100
@@ -170,8 +170,7 @@
                 }
             case '"':
             case '\\':
-                error(AbstractParser.message("unexpected.token", str));
-                break;
+                throw error(AbstractParser.message("unexpected.token", str));
             }
         }
 
@@ -222,14 +221,12 @@
                 return new UnaryNode(source, literalToken, LiteralNode.newInstance(source, realToken, finish, (Number)value));
             }
 
-            error(AbstractParser.message("expected", "number", type.getNameOrType()));
-            break;
+            throw error(AbstractParser.message("expected", "number", type.getNameOrType()));
         default:
             break;
         }
 
-        error(AbstractParser.message("expected", "json literal", type.getNameOrType()));
-        return null;
+        throw error(AbstractParser.message("expected", "json literal", type.getNameOrType()));
     }
 
     /**
@@ -265,7 +262,7 @@
                 elements.add(jsonLiteral());
                 // Comma between array elements is mandatory in JSON.
                 if (type != COMMARIGHT && type != RBRACKET) {
-                    error(AbstractParser.message("expected", ", or ]", type.getNameOrType()));
+                   throw error(AbstractParser.message("expected", ", or ]", type.getNameOrType()));
                 }
                 break;
             }
@@ -306,7 +303,7 @@
 
                 // Comma between property assigments is mandatory in JSON.
                 if (type != RBRACE && type != COMMARIGHT) {
-                    error(AbstractParser.message("expected", ", or }", type.getNameOrType()));
+                    throw error(AbstractParser.message("expected", ", or }", type.getNameOrType()));
                 }
                 break;
             }
@@ -334,13 +331,11 @@
         if (name != null) {
             expect(COLON);
             final Node value = jsonLiteral();
-            return new PropertyNode(source, propertyToken, value.getFinish(), name, value);
+            return new PropertyNode(source, propertyToken, value.getFinish(), name, value, null, null);
         }
 
         // Raise an error.
-        error(AbstractParser.message("expected", "string", type.getNameOrType()));
-
-        return null;
+        throw error(AbstractParser.message("expected", "string", type.getNameOrType()));
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java	Thu May 16 11:47:51 2013 +0100
@@ -57,6 +57,9 @@
  */
 @SuppressWarnings("fallthrough")
 public class Lexer extends Scanner {
+    private static final long MIN_INT_L = Integer.MIN_VALUE;
+    private static final long MAX_INT_L = Integer.MAX_VALUE;
+
     private static final boolean XML_LITERALS = Options.getBooleanProperty("nashorn.lexer.xmlliterals");
 
     /** Content source. */
@@ -984,27 +987,27 @@
      */
     private static Number valueOf(final String valueString, final int radix) throws NumberFormatException {
         try {
-            return Integer.valueOf(valueString, radix);
+            final long value = Long.parseLong(valueString, radix);
+            if(value >= MIN_INT_L && value <= MAX_INT_L) {
+                return Integer.valueOf((int)value);
+            }
+            return Long.valueOf(value);
         } catch (final NumberFormatException e) {
-            try {
-                return Long.valueOf(valueString, radix);
-            } catch (final NumberFormatException e2) {
-                if (radix == 10) {
-                    return Double.valueOf(valueString);
-                }
-
-                double value = 0.0;
+            if (radix == 10) {
+                return Double.valueOf(valueString);
+            }
 
-                for (int i = 0; i < valueString.length(); i++) {
-                    final char ch = valueString.charAt(i);
-                    // Preverified, should always be a valid digit.
-                    final int digit = convertDigit(ch, radix);
-                    value *= radix;
-                    value += digit;
-                }
+            double value = 0.0;
 
-                return value;
+            for (int i = 0; i < valueString.length(); i++) {
+                final char ch = valueString.charAt(i);
+                // Preverified, should always be a valid digit.
+                final int digit = convertDigit(ch, radix);
+                value *= radix;
+                value += digit;
             }
+
+            return value;
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java	Thu May 16 11:47:51 2013 +0100
@@ -54,24 +54,23 @@
 import static jdk.nashorn.internal.parser.TokenType.WHILE;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Stack;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockLexicalContext;
 import jdk.nashorn.internal.ir.BreakNode;
 import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.DoWhileNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.ForNode;
@@ -84,6 +83,7 @@
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LineNumberNode;
 import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
@@ -117,9 +117,10 @@
     /** Is scripting mode. */
     private final boolean scripting;
 
-    private final LexicalContext lexicalContext = new LexicalContext();
     private List<Node> functionDeclarations;
 
+    private final BlockLexicalContext lc = new BlockLexicalContext();
+
     /** Namespace for function names where not explicitly given */
     private final Namespace namespace;
 
@@ -146,7 +147,7 @@
      */
     public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) {
         super(source, errors, strict);
-        this.env   = env;
+        this.env       = env;
         this.namespace = new Namespace(env.getNamespace());
         this.scripting = env._scripting;
     }
@@ -162,7 +163,7 @@
      * @return function node resulting from successful parse
      */
     public FunctionNode parse() {
-        return parse(RUN_SCRIPT.tag());
+        return parse(RUN_SCRIPT.symbolName());
     }
 
     /**
@@ -176,7 +177,7 @@
      */
     public FunctionNode parse(final String scriptName) {
         final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
-        LOG.info(this + " begin for '" + scriptName + "'");
+        LOG.info(this, " begin for '", scriptName, "'");
 
         try {
             stream = new TokenStream();
@@ -214,7 +215,7 @@
              final String end = this + " end '" + scriptName + "'";
              if (Timing.isEnabled()) {
                  Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
-                 LOG.info(end + "' in " + (System.currentTimeMillis() - t0) + " ms");
+                 LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms");
              } else {
                  LOG.info(end);
              }
@@ -275,8 +276,7 @@
      */
     private Block newBlock() {
         final Block block = new Block(source, token, Token.descPosition(token));
-        lexicalContext.push(block);
-        return block;
+        return lc.push(block);
     }
 
     /**
@@ -285,36 +285,60 @@
      * @param ident Name of function.
      * @return New block.
      */
-    private FunctionNode newFunctionBlock(final IdentNode ident) {
+    private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
         // Build function name.
         final StringBuilder sb = new StringBuilder();
 
-        final FunctionNode parentFunction = getFunction();
-        if(parentFunction != null && !parentFunction.isProgram()) {
+        final FunctionNode parentFunction = lc.getCurrentFunction();
+        if (parentFunction != null && !parentFunction.isProgram()) {
             sb.append(parentFunction.getName()).append('$');
         }
 
-        sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
+        sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName());
         final String name = namespace.uniqueName(sb.toString());
-        assert parentFunction != null || name.equals(RUN_SCRIPT.tag())  : "name = " + name;// must not rename runScript().
+        assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName())  : "name = " + name;// must not rename runScript().
+
+        int flags = 0;
+        if (parentFunction == null) {
+            flags |= FunctionNode.IS_PROGRAM;
+        }
+        if (isStrictMode) {
+            flags |= FunctionNode.IS_STRICT;
+        }
 
         // Start new block.
-        final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
-        if(parentFunction == null) {
-            functionBlock.setProgram();
-        }
-        functionBlock.setStrictMode(isStrictMode);
-        functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
-        lexicalContext.push(functionBlock);
-
-        return functionBlock;
+        FunctionNode functionNode =
+            new FunctionNode(
+                source,
+                token,
+                Token.descPosition(token),
+                startToken,
+                namespace,
+                ident,
+                name,
+                parameters,
+                kind,
+                flags);
+
+        functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+        lc.push(functionNode);
+        // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
+        // FunctionNode.
+        newBlock();
+        return functionNode;
     }
 
     /**
      * Restore the current block.
      */
-    private void restoreBlock(Block block) {
-        lexicalContext.pop(block);
+    private Block restoreBlock(final Block block) {
+        return lc.pop(block);//.setFlag(lc, flags);
+    }
+
+    private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
+        final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
+
+        return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
     }
 
     /**
@@ -323,23 +347,17 @@
      */
     private Block getBlock(final boolean needsBraces) {
         // Set up new block. Captures LBRACE.
-        final Block newBlock = newBlock();
+        Block newBlock = newBlock();
         try {
-            pushControlNode(newBlock);
-
             // Block opening brace.
             if (needsBraces) {
                 expect(LBRACE);
             }
-
-            try {
-                // Accumulate block statements.
-                statementList();
-            } finally {
-                popControlNode();
-            }
+            // Accumulate block statements.
+            statementList();
+
         } finally {
-            restoreBlock(newBlock);
+            newBlock = restoreBlock(newBlock);
         }
 
         final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
@@ -363,15 +381,12 @@
             return getBlock(true);
         }
         // Set up new block. Captures first token.
-        final Block newBlock = newBlock();
-
+        Block newBlock = newBlock();
         try {
-            // Accumulate statements.
             statement();
         } finally {
-            restoreBlock(newBlock);
+            newBlock = restoreBlock(newBlock);
         }
-
         return newBlock;
     }
 
@@ -382,11 +397,8 @@
     private void detectSpecialFunction(final IdentNode ident) {
         final String name = ident.getName();
 
-        if (EVAL.tag().equals(name)) {
-            final Iterator<FunctionNode> it = lexicalContext.getFunctions();
-            if(it.hasNext()) {
-                it.next().setHasEval(it);
-            }
+        if (EVAL.symbolName().equals(name)) {
+            markEval(lc);
         }
     }
 
@@ -397,8 +409,8 @@
     private void detectSpecialProperty(final IdentNode ident) {
         final String name = ident.getName();
 
-        if (ARGUMENTS.tag().equals(name)) {
-            getFunction().setUsesArguments();
+        if (ARGUMENTS.symbolName().equals(name)) {
+            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
         }
     }
 
@@ -439,7 +451,7 @@
                   lhs instanceof IndexNode ||
                   lhs instanceof IdentNode)) {
                 if (env._early_lvalue_error) {
-                    error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
+                    throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
                 }
                 return referenceError(lhs, rhs);
             }
@@ -469,144 +481,14 @@
      * @return           Reduced expression.
      */
     private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
-        long incDecToken = firstToken;
         if (isPostfix) {
-            incDecToken = Token.recast(incDecToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX);
-        }
-
-        final UnaryNode node = new UnaryNode(source, incDecToken, expression);
-        if (isPostfix) {
-            node.setStart(expression.getStart());
-            node.setFinish(Token.descPosition(incDecToken) + Token.descLength(incDecToken));
-        }
-
-        return node;
-    }
-
-    /**
-     * Find a label node in the label stack.
-     * @param ident Ident to find.
-     * @return null or the found label node.
-     */
-    private LabelNode findLabel(final IdentNode ident) {
-        for (final LabelNode labelNode : getFunction().getLabelStack()) {
-            if (labelNode.getLabel().equals(ident)) {
-                return labelNode;
-            }
+            return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
         }
 
-        return null;
-    }
-
-    /**
-     * Add a label to the label stack.
-     * @param labelNode Label to add.
-     */
-    private void pushLabel(final LabelNode labelNode) {
-        getFunction().getLabelStack().push(labelNode);
-    }
-
-    /**
-      * Remove a label from the label stack.
-      */
-    private void popLabel() {
-        getFunction().getLabelStack().pop();
-    }
-
-    /**
-     * Track the current nesting of controls for break and continue.
-     * @param node For, while, do or switch node.
-     */
-    private void pushControlNode(final Node node) {
-        final boolean isLoop = node instanceof WhileNode;
-        final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
-        final FunctionNode function = getFunction();
-        function.getControlStack().push(node);
-
-        for (final LabelNode labelNode : function.getLabelStack()) {
-            if (isBreakable && labelNode.getBreakNode() == null) {
-                labelNode.setBreakNode(node);
-            }
-
-            if (isLoop && labelNode.getContinueNode() == null) {
-                labelNode.setContinueNode(node);
-            }
-        }
+        return new UnaryNode(source, firstToken, expression);
     }
 
     /**
-     * Finish with control.
-     */
-    private void popControlNode() {
-        // Get control stack.
-        final Stack<Node> controlStack = getFunction().getControlStack();
-
-        // Can be empty if missing brace.
-        if (!controlStack.isEmpty()) {
-            controlStack.pop();
-        }
-    }
-
-    private void popControlNode(final Node node) {
-        // Get control stack.
-        final Stack<Node> controlStack = getFunction().getControlStack();
-
-        // Can be empty if missing brace.
-        if (!controlStack.isEmpty() && controlStack.peek() == node) {
-            controlStack.pop();
-        }
-    }
-
-    private boolean isInWithBlock() {
-        final Stack<Node> controlStack = getFunction().getControlStack();
-        for (int i = controlStack.size() - 1; i >= 0; i--) {
-            final Node node = controlStack.get(i);
-
-            if (node instanceof WithNode) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    private <T extends Node> T findControl(final Class<T> ctype) {
-        final Stack<Node> controlStack = getFunction().getControlStack();
-        for (int i = controlStack.size() - 1; i >= 0; i--) {
-            final Node node = controlStack.get(i);
-
-            if (ctype.isAssignableFrom(node.getClass())) {
-                return ctype.cast(node);
-            }
-        }
-
-        return null;
-    }
-
-    private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
-        final List<T> nodes = new ArrayList<>();
-        final Stack<Node> controlStack = getFunction().getControlStack();
-        for (int i = controlStack.size() - 1; i >= 0; i--) {
-            final Node node = controlStack.get(i);
-
-            if (to == node) {
-                break; //stop looking
-            }
-
-            if (ctype.isAssignableFrom(node.getClass())) {
-                nodes.add(ctype.cast(node));
-            }
-        }
-
-        return nodes;
-    }
-
-    private <T extends Node> int countControls(final Class<T> ctype, final Node to) {
-        return findControls(ctype, to).size();
-    }
-
-
-    /**
      * -----------------------------------------------------------------------
      *
      * Grammar based on
@@ -630,18 +512,23 @@
         final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
         // Set up the script to append elements.
 
-        final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName));
-
-        script.setKind(FunctionNode.Kind.SCRIPT);
-        script.setFirstToken(functionToken);
+        FunctionNode script = newFunctionNode(
+            functionToken,
+            new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
+            new ArrayList<IdentNode>(),
+            FunctionNode.Kind.SCRIPT);
+
         functionDeclarations = new ArrayList<>();
         sourceElements();
-        script.prependStatements(functionDeclarations);
+        addFunctionDeclarations(script);
         functionDeclarations = null;
+
         expect(EOF);
-        script.setLastToken(token);
+
         script.setFinish(source.getLength() - 1);
 
+        script = restoreFunctionNode(script, token); //commit code
+        script = script.setBody(lc, script.getBody().setNeedsScope(lc));
         return script;
     }
 
@@ -670,24 +557,6 @@
     }
 
     /**
-     * Return last node in a statement list.
-     *
-     * @param statements Statement list.
-     *
-     * @return Last (non-debug) statement or null if empty block.
-     */
-    private static Node lastStatement(final List<Node> statements) {
-        for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
-            final Node node = statements.get(lastIndex);
-            if (!node.isDebug()) {
-                return node;
-            }
-        }
-
-        return null;
-    }
-
-    /**
      * SourceElements :
      *      SourceElement
      *      SourceElements SourceElement
@@ -716,7 +585,7 @@
                     // check for directive prologues
                     if (checkDirective) {
                         // skip any debug statement like line number to get actual first line
-                        final Node lastStatement = lastStatement(getBlock().getStatements());
+                        final Node lastStatement = lc.getLastStatement();
 
                         // get directive prologue, if any
                         final String directive = getDirective(lastStatement);
@@ -736,8 +605,8 @@
                             // handle use strict directive
                             if ("use strict".equals(directive)) {
                                 isStrictMode = true;
-                                final FunctionNode function = getFunction();
-                                function.setStrictMode(true);
+                                final FunctionNode function = lc.getCurrentFunction();
+                                lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
 
                                 // We don't need to check these, if lexical environment is already strict
                                 if (!oldStrictMode && directiveStmts != null) {
@@ -759,7 +628,7 @@
                         }
                     }
                 } catch (final Exception e) {
-                    // Recover parsing.
+                    //recover parsing
                     recover(e);
                 }
 
@@ -806,14 +675,13 @@
         if (type == FUNCTION) {
             // As per spec (ECMA section 12), function declarations as arbitrary statement
             // is not "portable". Implementation can issue a warning or disallow the same.
-            if (isStrictMode && !topLevel) {
-                error(AbstractParser.message("strict.no.func.here"), token);
-            }
             functionExpression(true, topLevel);
             return;
         }
 
-        getBlock().addStatement(lineNumberNode);
+        if (lineNumberNode != null) {
+            appendStatement(lineNumberNode);
+        }
 
         switch (type) {
         case LBRACE:
@@ -893,13 +761,9 @@
      * Parse a statement block.
      */
     private void block() {
-        // Get statements in block.
         final Block newBlock = getBlock(true);
-
         // Force block execution.
-        final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
-
-        getBlock().addStatement(executeNode);
+        appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
     }
 
     /**
@@ -942,7 +806,7 @@
             switch (ident.getName()) {
             case "eval":
             case "arguments":
-                error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
+                throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
             default:
                 break;
             }
@@ -995,8 +859,7 @@
             // Allocate var node.
             final VarNode var = new VarNode(source, varToken, finish, name, init);
             vars.add(var);
-            // Add to current block.
-            getBlock().addStatement(var);
+            appendStatement(var);
 
             if (type != COMMARIGHT) {
                 break;
@@ -1009,7 +872,7 @@
             boolean semicolon = type == SEMICOLON;
             endOfLine();
             if (semicolon) {
-                getBlock().setFinish(finish);
+                lc.getCurrentBlock().setFinish(finish);
             }
         }
 
@@ -1026,8 +889,7 @@
      */
     private void emptyStatement() {
         if (env._empty_statements) {
-            getBlock().addStatement(new EmptyNode(source, token,
-                    Token.descPosition(token) + Token.descLength(token)));
+            appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
         }
 
         // SEMICOLON checked in caller.
@@ -1052,7 +914,7 @@
         ExecuteNode executeNode = null;
         if (expression != null) {
             executeNode = new ExecuteNode(source, expressionToken, finish, expression);
-            getBlock().addStatement(executeNode);
+            appendStatement(executeNode);
         } else {
             expect(null);
         }
@@ -1061,7 +923,7 @@
 
         if (executeNode != null) {
             executeNode.setFinish(finish);
-            getBlock().setFinish(finish);
+            lc.getCurrentBlock().setFinish(finish);
         }
     }
 
@@ -1081,29 +943,17 @@
         next();
 
         expect(LPAREN);
-
-        // Get the test expression.
         final Node test = expression();
-
         expect(RPAREN);
-
-        // Get the pass statement.
         final Block pass = getStatement();
 
-        // Assume no else.
         Block fail = null;
-
         if (type == ELSE) {
             next();
-
-            // Get the else block.
             fail = getStatement();
         }
 
-        // Construct and add new if node.
-        final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
-
-        getBlock().addStatement(ifNode);
+        appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
     }
 
     /**
@@ -1120,12 +970,12 @@
      */
     private void forStatement() {
         // Create FOR node, capturing FOR token.
-        final ForNode forNode = new ForNode(source, token, Token.descPosition(token));
-
-        pushControlNode(forNode);
+        ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
+
 
         // Set up new block for scope of vars. Captures first token.
-        final Block outer = newBlock();
+        Block outer = newBlock();
+        lc.push(forNode);
 
         try {
             // FOR tested in caller.
@@ -1134,31 +984,97 @@
             // Nashorn extension: for each expression.
             // iterate property values rather than property names.
             if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
-                forNode.setIsForEach();
+                forNode = forNode.setIsForEach(lc);
                 next();
             }
 
             expect(LPAREN);
 
-            /// Capture control information.
-            forControl(forNode);
+            List<VarNode> vars = null;
+
+            switch (type) {
+            case VAR:
+                // Var statements captured in for outer block.
+                vars = variableStatement(false);
+                break;
+            case SEMICOLON:
+                break;
+            default:
+                final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
+                forNode = forNode.setInit(lc, expression);
+                break;
+            }
+
+            switch (type) {
+            case SEMICOLON:
+                // for (init; test; modify)
+                expect(SEMICOLON);
+                if (type != SEMICOLON) {
+                    forNode = forNode.setTest(lc, expression());
+                }
+                expect(SEMICOLON);
+                if (type != RPAREN) {
+                    forNode = forNode.setModify(lc, expression());
+                }
+                break;
+
+            case IN:
+                forNode = forNode.setIsForIn(lc);
+                if (vars != null) {
+                    // for (var i in obj)
+                    if (vars.size() == 1) {
+                        forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
+                    } else {
+                        // for (var i, j in obj) is invalid
+                        throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
+                    }
+
+                } else {
+                    // for (expr in obj)
+                    final Node init = forNode.getInit();
+                    assert init != null : "for..in init expression can not be null here";
+
+                    // check if initial expression is a valid L-value
+                    if (!(init instanceof AccessNode ||
+                          init instanceof IndexNode ||
+                          init instanceof IdentNode)) {
+                        throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
+                    }
+
+                    if (init instanceof IdentNode) {
+                        if (!checkIdentLValue((IdentNode)init)) {
+                            throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
+                        }
+                        verifyStrictIdent((IdentNode)init, "for-in iterator");
+                    }
+                }
+
+                next();
+
+                // Get the collection expression.
+                forNode = forNode.setModify(lc, expression());
+                break;
+
+            default:
+                expect(SEMICOLON);
+                break;
+            }
 
             expect(RPAREN);
 
             // Set the for body.
             final Block body = getStatement();
-            forNode.setBody(body);
+            forNode = forNode.setBody(lc, body);
             forNode.setFinish(body.getFinish());
             outer.setFinish(body.getFinish());
 
-            // Add for to current block.
-            getBlock().addStatement(forNode);
+            appendStatement(forNode);
         } finally {
-            restoreBlock(outer);
-            popControlNode();
+            lc.pop(forNode);
+            outer = restoreBlock(outer);
         }
 
-        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
      }
 
     /**
@@ -1175,87 +1091,7 @@
      * comprehensions.
      * @param forNode Owning FOR.
      */
-    private void forControl(final ForNode forNode) {
-        List<VarNode> vars = null;
-
-        switch (type) {
-        case VAR:
-            // Var statements captured in for outer block.
-            vars = variableStatement(false);
-            break;
-
-        case SEMICOLON:
-            break;
-
-        default:
-            final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
-            forNode.setInit(expression);
-        }
-
-        switch (type) {
-        case SEMICOLON:
-            // for (init; test; modify)
-            expect(SEMICOLON);
-
-            // Get the test expression.
-            if (type != SEMICOLON) {
-                forNode.setTest(expression());
-            }
-
-            expect(SEMICOLON);
-
-            // Get the modify expression.
-            if (type != RPAREN) {
-                final Node expression = expression();
-                forNode.setModify(expression);
-            }
-
-            break;
-
-        case IN:
-            forNode.setIsForIn();
-
-            if (vars != null) {
-                // for (var i in obj)
-                if (vars.size() == 1) {
-                    forNode.setInit(new IdentNode(vars.get(0).getName()));
-                } else {
-                    // for (var i, j in obj) is invalid
-                    error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
-                }
-
-            } else {
-                // for (expr in obj)
-                final Node init = forNode.getInit();
-                assert init != null : "for..in init expression can not be null here";
-
-                // check if initial expression is a valid L-value
-                if (!(init instanceof AccessNode ||
-                      init instanceof IndexNode ||
-                      init instanceof IdentNode)) {
-                    error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
-                }
-
-                if (init instanceof IdentNode) {
-                    if (!checkIdentLValue((IdentNode)init)) {
-                        error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
-                    }
-                    verifyStrictIdent((IdentNode)init, "for-in iterator");
-                }
-            }
-
-            next();
-
-            // Get the collection expression.
-            forNode.setModify(expression());
-            break;
-
-        default:
-            expect(SEMICOLON);
-            break;
-        }
-
-    }
+
 
     /**
      * ...IterationStatement :
@@ -1274,27 +1110,17 @@
         next();
 
         // Construct WHILE node.
-        final WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken));
-        pushControlNode(whileNode);
+        WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
+        lc.push(whileNode);
 
         try {
             expect(LPAREN);
-
-            // Get the test expression.
-            final Node test = expression();
-            whileNode.setTest(test);
-
+            whileNode = whileNode.setTest(lc, expression());
             expect(RPAREN);
-
-            // Get WHILE body.
-            final Block statements = getStatement();
-            whileNode.setBody(statements);
-            whileNode.setFinish(statements.getFinish());
-
-            // Add WHILE node.
-            getBlock().addStatement(whileNode);
+            whileNode = whileNode.setBody(lc, getStatement());
+            appendStatement(whileNode);
         } finally {
-            popControlNode();
+            lc.pop(whileNode);
         }
     }
 
@@ -1314,34 +1140,25 @@
         // DO tested in the caller.
         next();
 
-        final WhileNode doWhileNode = new DoWhileNode(source, doToken, Token.descPosition(doToken));
-        pushControlNode(doWhileNode);
+        WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
+        lc.push(doWhileNode);
 
         try {
            // Get DO body.
-            final Block statements = getStatement();
-            doWhileNode.setBody(statements);
+            doWhileNode = doWhileNode.setBody(lc, getStatement());
 
             expect(WHILE);
-
             expect(LPAREN);
-
-            // Get the test expression.
-            final Node test = expression();
-            doWhileNode.setTest(test);
-
+            doWhileNode = doWhileNode.setTest(lc, expression());
             expect(RPAREN);
 
             if (type == SEMICOLON) {
                 endOfLine();
             }
-
             doWhileNode.setFinish(finish);
-
-            // Add DO node.
-            getBlock().addStatement(doWhileNode);
+            appendStatement(doWhileNode);
         } finally {
-            popControlNode();
+            lc.pop(doWhileNode);
         }
     }
 
@@ -1370,28 +1187,26 @@
 
         default:
             final IdentNode ident = getIdent();
-            labelNode = findLabel(ident);
+            labelNode = lc.findLabel(ident.getName());
 
             if (labelNode == null) {
-                error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
+                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
             }
 
             break;
         }
 
-        final Node targetNode = labelNode != null ? labelNode.getContinueNode() : findControl(WhileNode.class);
+        final IdentNode label = labelNode == null ? null : labelNode.getLabel();
+        final LoopNode targetNode = lc.getContinueTo(label);
 
         if (targetNode == null) {
-            error(AbstractParser.message("illegal.continue.stmt"), continueToken);
+            throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
         }
 
         endOfLine();
 
         // Construct and add CONTINUE node.
-        final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
-        continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
-
-        getBlock().addStatement(continueNode);
+        appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1418,28 +1233,27 @@
 
         default:
             final IdentNode ident = getIdent();
-            labelNode = findLabel(ident);
+            labelNode = lc.findLabel(ident.getName());
 
             if (labelNode == null) {
-                error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
+                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
             }
 
             break;
         }
 
-        final Node targetNode = labelNode != null ? labelNode.getBreakNode() : findControl(BreakableNode.class);
-
+        //either an explicit label - then get its node or just a "break" - get first breakable
+        //targetNode is what we are breaking out from.
+        final IdentNode label = labelNode == null ? null : labelNode.getLabel();
+        final BreakableNode targetNode = lc.getBreakable(label);
         if (targetNode == null) {
-            error(AbstractParser.message("illegal.break.stmt"), breakToken);
+            throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
         }
 
         endOfLine();
 
         // Construct and add BREAK node.
-        final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
-        breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
-
-        getBlock().addStatement(breakNode);
+        appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
     }
 
     /**
@@ -1452,8 +1266,8 @@
      */
     private void returnStatement() {
         // check for return outside function
-        if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
-            error(AbstractParser.message("invalid.return"));
+        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
+            throw error(AbstractParser.message("invalid.return"));
         }
 
         // Capture RETURN token.
@@ -1478,8 +1292,7 @@
         endOfLine();
 
         // Construct and add RETURN node.
-        final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
-        getBlock().addStatement(returnNode);
+        appendStatement(new ReturnNode(source, returnToken, finish, expression));
     }
 
     /**
@@ -1513,8 +1326,7 @@
         endOfLine();
 
         // Construct and add YIELD node.
-        final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
-        getBlock().addStatement(yieldNode);
+        appendStatement(new ReturnNode(source, yieldToken, finish, expression));
     }
 
     /**
@@ -1533,35 +1345,23 @@
 
         // ECMA 12.10.1 strict mode restrictions
         if (isStrictMode) {
-            error(AbstractParser.message("strict.no.with"), withToken);
+            throw error(AbstractParser.message("strict.no.with"), withToken);
         }
 
         // Get WITH expression.
-        final WithNode withNode = new WithNode(source, withToken, finish, null, null);
-        final Iterator<FunctionNode> it = lexicalContext.getFunctions();
-        if(it.hasNext()) {
-            it.next().setHasWith(it);
-        }
+        WithNode withNode = new WithNode(source, withToken, finish);
 
         try {
-            pushControlNode(withNode);
-
+            lc.push(withNode);
             expect(LPAREN);
-
-            final Node expression = expression();
-            withNode.setExpression(expression);
-
+            withNode = withNode.setExpression(lc, expression());
             expect(RPAREN);
-
-            // Get WITH body.
-            final Block statements = getStatement();
-            withNode.setBody(statements);
-            withNode.setFinish(finish);
+            withNode = withNode.setBody(lc, getStatement());
         } finally {
-            popControlNode(withNode);
+            lc.pop(withNode);
         }
 
-        getBlock().addStatement(withNode);
+        appendStatement(withNode);
     }
 
     /**
@@ -1587,22 +1387,17 @@
      * Parse SWITCH statement.
      */
     private void switchStatement() {
-        // Capture SWITCH token.
         final long switchToken = token;
         // SWITCH tested in caller.
         next();
 
         // Create and add switch statement.
-        final SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken));
-        pushControlNode(switchNode);
+        SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
+        lc.push(switchNode);
 
         try {
             expect(LPAREN);
-
-            // Get switch expression.
-            final Node switchExpression = expression();
-            switchNode.setExpression(switchExpression);
-
+            switchNode = switchNode.setExpression(lc, expression());
             expect(RPAREN);
 
             expect(LBRACE);
@@ -1619,19 +1414,14 @@
                 switch (type) {
                 case CASE:
                     next();
-
-                    // Get case expression.
                     caseExpression = expression();
-
                     break;
 
                 case DEFAULT:
                     if (defaultCase != null) {
-                        error(AbstractParser.message("duplicate.default.in.switch"));
+                        throw error(AbstractParser.message("duplicate.default.in.switch"));
                     }
-
                     next();
-
                     break;
 
                 default:
@@ -1654,16 +1444,13 @@
                 cases.add(caseNode);
             }
 
-            switchNode.setCases(cases);
-            switchNode.setDefaultCase(defaultCase);
-
+            switchNode = switchNode.setCases(lc, cases, defaultCase);
             next();
-
             switchNode.setFinish(finish);
 
-            getBlock().addStatement(switchNode);
+            appendStatement(switchNode);
         } finally {
-            popControlNode();
+            lc.pop(switchNode);
         }
     }
 
@@ -1683,23 +1470,19 @@
 
         expect(COLON);
 
-        if (findLabel(ident) != null) {
-            error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
+        if (lc.findLabel(ident.getName()) != null) {
+            throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
         }
 
+        LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
         try {
-            // Create and add label.
-            final LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
-            pushLabel(labelNode);
-            // Get and save body.
-            final Block statements = getStatement();
-            labelNode.setBody(statements);
+            lc.push(labelNode);
+            labelNode = labelNode.setBody(lc, getStatement());
             labelNode.setFinish(finish);
-
-            getBlock().addStatement(labelNode);
+            appendStatement(labelNode);
         } finally {
-            // Remove label.
-            popLabel();
+            assert lc.peek() instanceof LabelNode;
+            lc.pop(labelNode);
         }
     }
 
@@ -1732,14 +1515,12 @@
         }
 
         if (expression == null) {
-            error(AbstractParser.message("expected.operand", type.getNameOrType()));
+            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
         }
 
         endOfLine();
 
-        // Construct and add THROW node.
-        final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
-        getBlock().addStatement(throwNode);
+        appendStatement(new ThrowNode(source, throwToken, finish, expression));
     }
 
     /**
@@ -1766,28 +1547,18 @@
         next();
 
         // Container block needed to act as target for labeled break statements
-        final Block outer = newBlock();
-        pushControlNode(outer);
+        Block outer = newBlock();
 
         // Create try.
-        final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class));
-        pushControlNode(tryNode);
 
         try {
-            // Get TRY body.
-            final Block tryBody = getBlock(true);
-
-            // Prepare to accumulate catches.
+            final Block       tryBody     = getBlock(true);
             final List<Block> catchBlocks = new ArrayList<>();
 
             while (type == CATCH) {
-                // Capture CATCH token.
                 final long catchToken = token;
                 next();
-
                 expect(LPAREN);
-
-                // Get exception ident.
                 final IdentNode exception = getIdent();
 
                 // ECMA 12.4.1 strict mode restrictions
@@ -1795,28 +1566,23 @@
 
                 // Check for conditional catch.
                 Node ifExpression = null;
-
                 if (type == IF) {
                     next();
-
                     // Get the exception condition.
                     ifExpression = expression();
                 }
 
                 expect(RPAREN);
 
-                final Block catchBlock = newBlock();
+                Block catchBlock = newBlock();
                 try {
-
                     // Get CATCH body.
                     final Block catchBody = getBlock(true);
-
-                    // Create and add catch.
                     final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
-                    getBlock().addStatement(catchNode);
+                    appendStatement(catchNode);
+                } finally {
+                    catchBlock = restoreBlock(catchBlock);
                     catchBlocks.add(catchBlock);
-                } finally {
-                    restoreBlock(catchBlock);
                 }
 
                 // If unconditional catch then should to be the end.
@@ -1825,38 +1591,32 @@
                 }
             }
 
-            popControlNode();
-
             // Prepare to capture finally statement.
             Block finallyStatements = null;
 
             if (type == FINALLY) {
                 next();
-
-                // Get FINALLY body.
                 finallyStatements = getBlock(true);
             }
 
             // Need at least one catch or a finally.
             if (catchBlocks.isEmpty() && finallyStatements == null) {
-                error(AbstractParser.message("missing.catch.or.finally"), tryToken);
+                throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
             }
 
-            tryNode.setBody(tryBody);
-            tryNode.setCatchBlocks(catchBlocks);
-            tryNode.setFinallyBody(finallyStatements);
+            final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
+            // Add try.
+            assert lc.peek() == outer;
+            appendStatement(tryNode);
+
             tryNode.setFinish(finish);
             outer.setFinish(finish);
 
-            // Add try.
-            outer.addStatement(tryNode);
         } finally {
-            popControlNode(tryNode);
-            restoreBlock(outer);
-            popControlNode(outer);
+            outer = restoreBlock(outer);
         }
 
-        getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+        appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
     }
 
     /**
@@ -1872,11 +1632,8 @@
         final long debuggerToken = token;
         // DEBUGGER tested in caller.
         next();
-
         endOfLine();
-
-        final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
-        getBlock().addStatement(runtimeNode);
+        appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
     }
 
     /**
@@ -1912,7 +1669,7 @@
             return ident;
         case OCTAL:
             if (isStrictMode) {
-               error(AbstractParser.message("strict.no.octal"), token);
+               throw error(AbstractParser.message("strict.no.octal"), token);
             }
         case STRING:
         case ESCSTRING:
@@ -2036,7 +1793,7 @@
 
             default:
                 if (!elision) {
-                    error(AbstractParser.message("expected.comma", type.getNameOrType()));
+                    throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
                 }
                 // Add expression element.
                 final Node expression = assignmentExpression(false);
@@ -2077,8 +1834,8 @@
 
         // Object context.
         // Prepare to accumulate elements.
-        final List<Node> elements = new ArrayList<>();
-        final Map<Object, PropertyNode> map = new HashMap<>();
+       // final List<Node> elements = new ArrayList<>();
+        final Map<String, PropertyNode> map = new LinkedHashMap<>();
 
         // Create a block for the object literal.
             boolean commaSeen = true;
@@ -2096,25 +1853,30 @@
 
                 default:
                     if (!commaSeen) {
-                        error(AbstractParser.message("expected.comma", type.getNameOrType()));
-                }
-
-                commaSeen = false;
-                // Get and add the next property.
-                final PropertyNode property = propertyAssignment();
-                final Object key = property.getKeyName();
-                final PropertyNode existingProperty = map.get(key);
-
-                if (existingProperty != null) {
+                        throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
+                    }
+
+                    commaSeen = false;
+                    // Get and add the next property.
+                    final PropertyNode property = propertyAssignment();
+                    final String key = property.getKeyName();
+                    final PropertyNode existingProperty = map.get(key);
+
+                    if (existingProperty == null) {
+                        map.put(key, property);
+                       // elements.add(property);
+                        break;
+                    }
+
                     // ECMA section 11.1.5 Object Initialiser
                     // point # 4 on property assignment production
-                    final Node value  = property.getValue();
-                    final Node getter = property.getGetter();
-                    final Node setter = property.getSetter();
-
-                    final Node prevValue  = existingProperty.getValue();
-                    final Node prevGetter = existingProperty.getGetter();
-                    final Node prevSetter = existingProperty.getSetter();
+                    final Node         value  = property.getValue();
+                    final FunctionNode getter = property.getGetter();
+                    final FunctionNode setter = property.getSetter();
+
+                    final Node         prevValue  = existingProperty.getValue();
+                    final FunctionNode prevGetter = existingProperty.getGetter();
+                    final FunctionNode prevSetter = existingProperty.getSetter();
 
                     boolean redefinitionOk = true;
                     // ECMA 11.1.5 strict mode restrictions
@@ -2125,7 +1887,7 @@
                     }
 
                     final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
-                    final boolean isAccessor = getter != null || setter != null;
+                    final boolean isAccessor     = getter != null     || setter != null;
 
                     // data property redefined as accessor property
                     if (prevValue != null && isAccessor) {
@@ -2145,40 +1907,33 @@
                     }
 
                     if (!redefinitionOk) {
-                        error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
+                        throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
                     }
 
+                    PropertyNode newProperty = existingProperty;
                     if (value != null) {
-                        final Node existingValue = existingProperty.getValue();
-
-                        if (existingValue == null) {
-                            existingProperty.setValue(value);
+                        if (prevValue == null) {
+                            map.put(key, newProperty = newProperty.setValue(value));
                         } else {
-                            final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT);
-                            existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value));
+                            final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
+                            map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
                         }
 
-                        existingProperty.setGetter(null);
-                        existingProperty.setSetter(null);
+                        map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
                     }
 
                     if (getter != null) {
-                        existingProperty.setGetter(getter);
+                        map.put(key, newProperty = newProperty.setGetter(getter));
                     }
 
                     if (setter != null) {
-                        existingProperty.setSetter(setter);
+                        map.put(key, newProperty = newProperty.setSetter(setter));
                     }
-                } else {
-                    map.put(key, property);
-                    elements.add(property);
-                }
-
-                break;
+                    break;
             }
         }
 
-        return new ObjectNode(source, objectToken, finish, elements);
+        return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
     }
 
     /**
@@ -2198,7 +1953,7 @@
             return getIdent();
         case OCTAL:
             if (isStrictMode) {
-                error(AbstractParser.message("strict.no.octal"), token);
+                throw error(AbstractParser.message("strict.no.octal"), token);
             }
         case STRING:
         case ESCSTRING:
@@ -2235,8 +1990,6 @@
         final long propertyToken = token;
 
         FunctionNode functionNode;
-        List<IdentNode> parameters;
-        PropertyNode propertyNode;
         PropertyKey propertyName;
 
         if (type == IDENT) {
@@ -2253,11 +2006,8 @@
                     final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
                     expect(LPAREN);
                     expect(RPAREN);
-                    parameters = new ArrayList<>();
-                    functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
-                    propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
-                    propertyNode.setGetter(functionNode);
-                    return propertyNode;
+                    functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
+                    return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
 
                 case "set":
                     final PropertyKey setIdent = propertyName();
@@ -2267,12 +2017,10 @@
                     final IdentNode argIdent = getIdent();
                     verifyStrictIdent(argIdent, "setter argument");
                     expect(RPAREN);
-                    parameters = new ArrayList<>();
+                    List<IdentNode> parameters = new ArrayList<>();
                     parameters.add(argIdent);
                     functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
-                    propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
-                    propertyNode.setSetter(functionNode);
-                    return propertyNode;
+                    return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
 
                 default:
                     break;
@@ -2286,9 +2034,7 @@
 
         expect(COLON);
 
-        final Node value = assignmentExpression(false);
-        propertyNode =  new PropertyNode(source, propertyToken, finish, propertyName, value);
-        return propertyNode;
+        return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
     }
 
     /**
@@ -2321,9 +2067,6 @@
             }
 
             lhs = new CallNode(source, callToken, finish, lhs, arguments);
-            if (isInWithBlock()) {
-                ((CallNode)lhs).setInWithBlock();
-            }
         }
 
 loop:
@@ -2338,9 +2081,6 @@
 
                 // Create call node.
                 lhs = new CallNode(source, callToken, finish, lhs, arguments);
-                if (isInWithBlock()) {
-                    ((CallNode)lhs).setInWithBlock();
-                }
 
                 break;
 
@@ -2420,9 +2160,6 @@
         }
 
         final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments);
-        if (isInWithBlock()) {
-            callNode.setInWithBlock();
-        }
 
         return new UnaryNode(source, newToken, callNode);
     }
@@ -2482,8 +2219,7 @@
 
             case PERIOD:
                 if (lhs == null) {
-                    error(AbstractParser.message("expected.operand", type.getNameOrType()));
-                    return null;
+                    throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
                 }
 
                 next();
@@ -2585,29 +2321,33 @@
         }
 
         expect(LPAREN);
-
         final List<IdentNode> parameters = formalParameterList();
-
         expect(RPAREN);
 
-        final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
+        FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
 
         if (isStatement) {
-            if(topLevel) {
-                functionNode.setIsDeclared();
+            if (topLevel) {
+                functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
+            } else if (isStrictMode) {
+                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
+            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
+                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
+            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
+                warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
             }
-            if(ARGUMENTS.tag().equals(name.getName())) {
-                getFunction().setDefinesArguments();
+            if (ARGUMENTS.symbolName().equals(name.getName())) {
+                lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
         if (isAnonymous) {
-            functionNode.setIsAnonymous();
+            functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
         }
 
         final int arity = parameters.size();
 
-        final boolean strict = functionNode.isStrictMode();
+        final boolean strict = functionNode.isStrict();
         if (arity > 1) {
             final HashSet<String> parametersSet = new HashSet<>(arity);
 
@@ -2615,39 +2355,37 @@
                 final IdentNode parameter = parameters.get(i);
                 String parameterName = parameter.getName();
 
-                if (ARGUMENTS.tag().equals(parameterName)) {
-                    functionNode.setDefinesArguments();
+                if (ARGUMENTS.symbolName().equals(parameterName)) {
+                    functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
                 }
 
                 if (parametersSet.contains(parameterName)) {
                     // redefinition of parameter name
                     if (strict) {
-                        error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
-                    } else {
-                        // rename in non-strict mode
-                        parameterName = functionNode.uniqueName(parameterName);
-                        final long parameterToken = parameter.getToken();
-                        parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+                        throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
                     }
+                    // rename in non-strict mode
+                    parameterName = functionNode.uniqueName(parameterName);
+                    final long parameterToken = parameter.getToken();
+                    parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
                 }
 
                 parametersSet.add(parameterName);
             }
         } else if (arity == 1) {
-            if (ARGUMENTS.tag().equals(parameters.get(0).getName())) {
-                functionNode.setDefinesArguments();
+            if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) {
+                functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
             }
         }
 
         if (isStatement) {
-            final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
-            if(topLevel) {
+            final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
+            if (topLevel) {
                 functionDeclarations.add(lineNumber);
                 functionDeclarations.add(varNode);
             } else {
-                final Block block = getBlock();
-                block.addStatement(lineNumber);
-                block.addStatement(varNode);
+                appendStatement(lineNumber);
+                appendStatement(varNode);
             }
         }
 
@@ -2701,13 +2439,11 @@
      */
     private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
         FunctionNode functionNode = null;
+        long lastToken = 0L;
 
         try {
             // Create a new function block.
-            functionNode = newFunctionBlock(ident);
-            functionNode.setParameters(parameters);
-            functionNode.setKind(kind);
-            functionNode.setFirstToken(firstToken);
+            functionNode = newFunctionNode(firstToken, ident, parameters, kind);
 
             // Nashorn extension: expression closures
             if (!env._no_syntax_extensions && type != LBRACE) {
@@ -2720,14 +2456,12 @@
 
                 // just expression as function body
                 final Node expr = expression();
-
+                assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
                 // create a return statement - this creates code in itself and does not need to be
                 // wrapped into an ExecuteNode
-                final ReturnNode  returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null);
-
-                // add the return statement
-                functionNode.addStatement(returnNode);
-                functionNode.setLastToken(token);
+                final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
+                appendStatement(returnNode);
+                lastToken = token;
                 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
 
             } else {
@@ -2738,23 +2472,35 @@
                 functionDeclarations = new ArrayList<>();
                 try {
                     sourceElements();
-                    functionNode.prependStatements(functionDeclarations);
+                    addFunctionDeclarations(functionNode);
                 } finally {
                     functionDeclarations = prevFunctionDecls;
                 }
 
-                functionNode.setLastToken(token);
+                lastToken = token;
                 expect(RBRACE);
                 functionNode.setFinish(finish);
 
             }
         } finally {
-            restoreBlock(functionNode);
+            functionNode = restoreFunctionNode(functionNode, lastToken);
         }
-
         return functionNode;
     }
 
+    private void addFunctionDeclarations(final FunctionNode functionNode) {
+        assert lc.peek() == lc.getFunctionBody(functionNode);
+        VarNode lastDecl = null;
+        for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
+            Node decl = functionDeclarations.get(i);
+            if (lastDecl == null && decl instanceof VarNode) {
+                decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
+                lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
+            }
+            prependStatement(decl);
+        }
+    }
+
     private RuntimeNode referenceError(final Node lhs, final Node rhs) {
         final ArrayList<Node> args = new ArrayList<>();
         args.add(lhs);
@@ -2764,9 +2510,7 @@
             args.add(rhs);
         }
         args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
-        final RuntimeNode runtimeNode = new RuntimeNode(source, lhs.getToken(),
-                      lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
-        return runtimeNode;
+        return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
     }
 
     /*
@@ -2815,19 +2559,7 @@
         case BIT_NOT:
         case NOT:
             next();
-
             final Node expr = unaryExpression();
-
-            /*
-             // Not sure if "delete <ident>" is a compile-time error or a
-             // runtime error in strict mode.
-
-             if (isStrictMode) {
-                 if (unaryTokenType == DELETE && expr instanceof IdentNode) {
-                     error(message("strict.cant.delete.ident", ((IdentNode)expr).getName()), expr.getToken());
-                 }
-             }
-             */
             return new UnaryNode(source, unaryToken, expr);
 
         case INCPREFIX:
@@ -2890,7 +2622,7 @@
         }
 
         if (expression == null) {
-            error(AbstractParser.message("expected.operand", type.getNameOrType()));
+            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
         }
 
         return expression;
@@ -2992,6 +2724,7 @@
         // Include commas in expression parsing.
         return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
     }
+
     private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) {
         // Get the precedence of the next operator.
         int precedence = type.getPrecedence();
@@ -3087,11 +2820,26 @@
         return "[JavaScript Parsing]";
     }
 
-    private Block getBlock() {
-        return lexicalContext.getCurrentBlock();
+    private static void markEval(final LexicalContext lc) {
+        final Iterator<FunctionNode> iter = lc.getFunctions();
+        boolean flaggedCurrentFn = false;
+        while (iter.hasNext()) {
+            final FunctionNode fn = iter.next();
+            if (!flaggedCurrentFn) {
+                lc.setFlag(fn, FunctionNode.HAS_EVAL);
+                flaggedCurrentFn = true;
+            } else {
+                lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
+            }
+            lc.setFlag(lc.getFunctionBody(fn), Block.NEEDS_SCOPE);
+        }
     }
 
-    private FunctionNode getFunction() {
-        return lexicalContext.getCurrentFunction();
+    private void prependStatement(final Node statement) {
+        lc.prependStatement(statement);
+    }
+
+    private void appendStatement(final Node statement) {
+        lc.appendStatement(statement);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/parser/TokenType.java	Thu May 16 11:47:51 2013 +0100
@@ -280,6 +280,11 @@
        return values;
     }
 
+    @Override
+    public String toString() {
+        return name;
+    }
+
     static {
         // Avoid cloning of enumeration.
         values = TokenType.values();
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu May 16 11:47:51 2013 +0100
@@ -54,10 +54,24 @@
  * @see SpillProperty
  */
 public class AccessorProperty extends Property {
+    private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
     private static final MethodHandle REPLACE_MAP = findOwnMH("replaceMap", Object.class, Object.class, PropertyMap.class, String.class, Class.class, Class.class);
 
     private static final int NOOF_TYPES = getNumberOfAccessorTypes();
 
+    /**
+     * Properties in different maps for the same structure class will share their field getters and setters. This could
+     * be further extended to other method handles that are looked up in the AccessorProperty constructor, but right now
+     * these are the most frequently retrieved ones, and lookup of method handle natives only registers in the profiler
+     * for them.
+     */
+    private static ClassValue<GettersSetters> GETTERS_SETTERS = new ClassValue<GettersSetters>() {
+        @Override
+        protected GettersSetters computeValue(Class<?> structure) {
+            return new GettersSetters(structure);
+        }
+    };
+
     /** Property getter cache */
     private MethodHandle[] getters = new MethodHandle[NOOF_TYPES];
 
@@ -152,6 +166,22 @@
         setCurrentType(getterType);
     }
 
+    private static class GettersSetters {
+        final MethodHandle[] getters;
+        final MethodHandle[] setters;
+
+        public GettersSetters(Class<?> structure) {
+            final int fieldCount = ObjectClassGenerator.getFieldCount(structure);
+            getters = new MethodHandle[fieldCount];
+            setters = new MethodHandle[fieldCount];
+            for(int i = 0; i < fieldCount; ++i) {
+                final String fieldName = ObjectClassGenerator.getFieldName(i, Type.OBJECT);
+                getters[i] = MH.getter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
+                setters[i] = MH.setter(lookup, structure, fieldName, Type.OBJECT.getTypeClass());
+            }
+        }
+    }
+
     /**
      * Constructor for dual field AccessorPropertys.
      *
@@ -171,22 +201,19 @@
         primitiveGetter = null;
         primitiveSetter = null;
 
-        final MethodHandles.Lookup lookup = MethodHandles.lookup();
-
         if (isParameter() && hasArguments()) {
-            final MethodHandle arguments   = MH.getter(MethodHandles.lookup(), structure, "arguments", Object.class);
+            final MethodHandle arguments   = MH.getter(lookup, structure, "arguments", Object.class);
             final MethodHandle argumentsSO = MH.asType(arguments, arguments.type().changeReturnType(ScriptObject.class));
 
             objectGetter = MH.insertArguments(MH.filterArguments(ScriptObject.GET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
             objectSetter = MH.insertArguments(MH.filterArguments(ScriptObject.SET_ARGUMENT.methodHandle(), 0, argumentsSO), 1, slot);
         } else {
-            final String fieldNameObject    = ObjectClassGenerator.getFieldName(slot, Type.OBJECT);
-            final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
-
-            objectGetter = MH.getter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
-            objectSetter = MH.setter(lookup, structure, fieldNameObject, Type.OBJECT.getTypeClass());
+            final GettersSetters gs = GETTERS_SETTERS.get(structure);
+            objectGetter = gs.getters[slot];
+            objectSetter = gs.setters[slot];
 
             if (!OBJECT_FIELDS_ONLY) {
+                final String fieldNamePrimitive = ObjectClassGenerator.getFieldName(slot, ObjectClassGenerator.PRIMITIVE_TYPE);
                 primitiveGetter = MH.getter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
                 primitiveSetter = MH.setter(lookup, structure, fieldNamePrimitive, PRIMITIVE_TYPE.getTypeClass());
             }
@@ -365,7 +392,7 @@
     }
 
     private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
-        return MH.findStatic(MethodHandles.lookup(), AccessorProperty.class, name, MH.type(rtype, types));
+        return MH.findStatic(lookup, AccessorProperty.class, name, MH.type(rtype, types));
     }
 
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java	Thu May 16 11:47:51 2013 +0100
@@ -54,10 +54,7 @@
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.parser.Parser;
-import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
 import jdk.nashorn.internal.runtime.options.Options;
-import sun.reflect.CallerSensitive;
-import sun.reflect.Reflection;
 
 /**
  * This class manages the global state of execution. Context is immutable.
@@ -114,24 +111,9 @@
      * Get the current global scope
      * @return the current global scope
      */
-    @CallerSensitive
     public static ScriptObject getGlobal() {
-        final SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            // skip getCallerClass and getGlobal and get to the real caller
-            Class<?> caller = Reflection.getCallerClass();
-            ClassLoader callerLoader = caller.getClassLoader();
-
-            // Allow this method only for nashorn's own classes, objects
-            // package classes and Java adapter classes. Rest should
-            // have the necessary security permission.
-            if (callerLoader != myLoader &&
-                !(callerLoader instanceof StructureLoader) &&
-                !(JavaAdapterFactory.isAdapterClass(caller))) {
-                sm.checkPermission(new RuntimePermission("nashorn.getGlobal"));
-            }
-        }
-
+        // This class in a package.access protected package.
+        // Trusted code only can call this method.
         return getGlobalTrusted();
     }
 
@@ -399,7 +381,7 @@
             // We need to get strict mode flag from compiled class. This is
             // because eval code may start with "use strict" directive.
             try {
-                strictFlag = clazz.getField(STRICT_MODE.tag()).getBoolean(null);
+                strictFlag = clazz.getField(STRICT_MODE.symbolName()).getBoolean(null);
             } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
                 //ignored
                 strictFlag = false;
@@ -432,6 +414,28 @@
         return ScriptRuntime.apply(func, evalThis);
     }
 
+    private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) {
+        if (srcStr.startsWith(prefix)) {
+            final String resource = resourcePath + srcStr.substring(prefix.length());
+            // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
+            // These scripts are always available and are loaded from nashorn.jar's resources.
+            return AccessController.doPrivileged(
+                    new PrivilegedAction<Source>() {
+                        @Override
+                        public Source run() {
+                            try {
+                                final URL resURL = Context.class.getResource(resource);
+                                return (resURL != null)? new Source(srcStr, resURL) : null;
+                            } catch (final IOException exp) {
+                                return null;
+                            }
+                        }
+                    });
+        }
+
+        return null;
+    }
+
     /**
      * Implementation of {@code load} Nashorn extension. Load a script file from a source
      * expression
@@ -444,33 +448,18 @@
      * @throws IOException if source cannot be found or loaded
      */
     public Object load(final ScriptObject scope, final Object from) throws IOException {
-        Object src = (from instanceof ConsString)?  from.toString() : from;
+        final Object src = (from instanceof ConsString)?  from.toString() : from;
         Source source = null;
 
         // load accepts a String (which could be a URL or a file name), a File, a URL
         // or a ScriptObject that has "name" and "source" (string valued) properties.
         if (src instanceof String) {
             final String srcStr = (String)src;
-            final File   file   = new File(srcStr);
+            final File file = new File(srcStr);
             if (srcStr.indexOf(':') != -1) {
-                if (srcStr.startsWith("nashorn:")) {
-                    final String resource = "resources/" + srcStr.substring("nashorn:".length());
-                    // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme
-                    // These scripts are always available and are loaded from nashorn.jar's resources.
-                    source = AccessController.doPrivileged(
-                            new PrivilegedAction<Source>() {
-                                @Override
-                                public Source run() {
-                                    try {
-                                        final URL resURL = Context.class.getResource(resource);
-                                        return (resURL != null)? new Source(srcStr, resURL) : null;
-                                    } catch (final IOException exp) {
-                                        return null;
-                                    }
-                                }
-                            });
-                } else {
-                    URL url = null;
+                if ((source = loadInternal(srcStr, "nashorn:", "resources/")) == null &&
+                    (source = loadInternal(srcStr, "fx:", "resources/fx/")) == null) {
+                    URL url;
                     try {
                         //check for malformed url. if malformed, it may still be a valid file
                         url = new URL(srcStr);
@@ -713,7 +702,7 @@
                 MH.findStatic(
                     MethodHandles.lookup(),
                     script,
-                    RUN_SCRIPT.tag(),
+                    RUN_SCRIPT.symbolName(),
                     MH.type(
                         Object.class,
                         ScriptFunction.class,
@@ -722,13 +711,13 @@
         boolean strict;
 
         try {
-            strict = script.getField(STRICT_MODE.tag()).getBoolean(null);
+            strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null);
         } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
             strict = false;
         }
 
         // Package as a JavaScript function and pass function back to shell.
-        return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict);
+        return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict);
     }
 
     private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) {
@@ -746,13 +735,13 @@
             global = (GlobalObject)Context.getGlobalTrusted();
             script = global.findCachedClass(source);
             if (script != null) {
-                Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile.");
+                Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile.");
                 return script;
             }
         }
 
         final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse();
-        if (errors.hasErrors() || env._parse_only) {
+        if (errors.hasErrors()) {
             return null;
         }
 
@@ -764,6 +753,10 @@
             getErr().println(new PrintVisitor(functionNode));
         }
 
+        if (env._parse_only) {
+            return null;
+        }
+
         final URL          url    = source.getURL();
         final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
         final CodeSource   cs     = url == null ? null : new CodeSource(url, (CodeSigner[])null);
--- a/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/DebugLogger.java	Thu May 16 11:47:51 2013 +0100
@@ -135,7 +135,16 @@
      * @param str the string to log
      */
     public void finest(final String str) {
-        log(str, Level.FINEST);
+        log(Level.FINEST, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINEST} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void finest(final Object... objs) {
+        log(Level.FINEST, objs);
     }
 
     /**
@@ -144,7 +153,16 @@
      * @param str the string to log
      */
     public void finer(final String str) {
-        log(str, Level.FINER);
+        log(Level.FINER, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINER} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void finer(final Object... objs) {
+        log(Level.FINER, objs);
     }
 
     /**
@@ -153,7 +171,16 @@
      * @param str the string to log
      */
     public void fine(final String str) {
-        log(str, Level.FINE);
+        log(Level.FINE, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void fine(final Object... objs) {
+        log(Level.FINE, objs);
     }
 
     /**
@@ -162,7 +189,16 @@
      * @param str the string to log
      */
     public void config(final String str) {
-        log(str, Level.CONFIG);
+        log(Level.CONFIG, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#CONFIG} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void config(final Object... objs) {
+        log(Level.CONFIG, objs);
     }
 
     /**
@@ -171,7 +207,16 @@
      * @param str the string to log
      */
     public void info(final String str) {
-        log(str, Level.INFO);
+        log(Level.INFO, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void info(final Object... objs) {
+        log(Level.INFO, objs);
     }
 
     /**
@@ -180,7 +225,16 @@
      * @param str the string to log
      */
     public void warning(final String str) {
-        log(str, Level.WARNING);
+        log(Level.WARNING, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void warning(final Object... objs) {
+        log(Level.WARNING, objs);
     }
 
     /**
@@ -189,20 +243,28 @@
      * @param str the string to log
      */
     public void severe(final String str) {
-        log(str, Level.SEVERE);
+        log(Level.SEVERE, str);
+    }
+
+    /**
+     * Shorthand for outputting a log string as log level
+     * {@link java.util.logging.Level#FINE} on this logger
+     * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead
+     */
+    public void severe(final Object... objs) {
+        log(Level.SEVERE, objs);
     }
 
     /**
      * Output log line on this logger at a given level of verbosity
      * @see java.util.logging.Level
      *
+     * @param level minimum log level required for logging to take place
      * @param str   string to log
-     * @param level minimum log level required for logging to take place
      */
-    public void log(final String str, final Level level) {
+    public void log(final Level level, final String str) {
         if (isEnabled) {
             final StringBuilder sb = new StringBuilder();
-
             for (int i = 0 ; i < indent ; i++) {
                 sb.append(' ');
             }
@@ -210,4 +272,24 @@
             logger.log(level, sb.toString());
         }
     }
+
+    /**
+     * Output log line on this logger at a given level of verbosity
+     * @see java.util.logging.Level
+     *
+     * @param level minimum log level required for logging to take place
+     * @param objs  objects for which to invoke toString and concatenate to log
+     */
+    public void log(final Level level, final Object... objs) {
+        if (isEnabled) {
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0 ; i < indent ; i++) {
+                sb.append(' ');
+            }
+            for (final Object obj : objs) {
+                sb.append(obj);
+            }
+            logger.log(level, sb.toString());
+        }
+    }
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java	Thu May 16 11:47:51 2013 +0100
@@ -105,6 +105,22 @@
     }
 
     /**
+     * Return the appropriate receiver for a getter.
+     * @return appropriate receiver
+     */
+    public ScriptObject getGetterReceiver() {
+        return property != null && property.hasGetterFunction() ? self : prototype;
+    }
+
+   /**
+     * Return the appropriate receiver for a setter.
+     * @return appropriate receiver
+     */
+    public ScriptObject getSetterReceiver() {
+        return property != null && property.hasSetterFunction() ? self : prototype;
+    }
+
+    /**
      * Return the property that was found
      * @return property
      */
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu May 16 11:47:51 2013 +0100
@@ -105,9 +105,7 @@
     // This is the abstract "Walk" operation from the spec.
     private static Object walk(final ScriptObject holder, final Object name, final ScriptFunction reviver) {
         final Object val = holder.get(name);
-        if (val == ScriptRuntime.UNDEFINED) {
-            return val;
-        } else if (val instanceof ScriptObject) {
+        if (val instanceof ScriptObject) {
             final ScriptObject     valueObj = (ScriptObject)val;
             final boolean          strict   = valueObj.isStrictContext();
             final Iterator<String> iter     = valueObj.propertyIterator();
@@ -122,33 +120,15 @@
                     valueObj.set(key, newElement, strict);
                 }
             }
-
-            return valueObj;
-        } else if (isArray(val)) {
-            final ScriptObject      valueArray = (ScriptObject)val;
-            final boolean          strict     = valueArray.isStrictContext();
-            final Iterator<String> iter       = valueArray.propertyIterator();
-
-            while (iter.hasNext()) {
-                final String key        = iter.next();
-                final Object newElement = walk(valueArray, valueArray.get(key), reviver);
+        }
 
-                if (newElement == ScriptRuntime.UNDEFINED) {
-                    valueArray.delete(key, strict);
-                } else {
-                    valueArray.set(key, newElement, strict);
-                }
-            }
-            return valueArray;
-        } else {
-            try {
-                // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class);
-                return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val);
-            } catch(Error|RuntimeException t) {
-                throw t;
-            } catch(final Throwable t) {
-                throw new RuntimeException(t);
-            }
+        try {
+             // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class);
+             return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val);
+        } catch(Error|RuntimeException t) {
+            throw t;
+        } catch(final Throwable t) {
+            throw new RuntimeException(t);
         }
     }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java	Thu May 16 11:47:51 2013 +0100
@@ -102,6 +102,8 @@
     /** JavaScript compliant conversion function from Object to primitive */
     public static final Call TO_PRIMITIVE = staticCall(JSType.class, "toPrimitive", Object.class,  Object.class);
 
+    private static final double INT32_LIMIT = 4294967296.0;
+
     /**
      * The external type name as returned by ECMAScript "typeof" operator
      *
@@ -612,10 +614,7 @@
      * @return an int32
      */
     public static int toInt32(final double num) {
-        if (Double.isInfinite(num)) {
-            return 0;
-        }
-        return (int)(long)num;
+        return (int)doubleToInt32(num);
     }
 
     /**
@@ -658,10 +657,7 @@
      * @return a uint32
      */
     public static long toUint32(final double num) {
-        if (Double.isInfinite(num)) {
-            return 0L;
-        }
-        return ((long)num) & 0xffff_ffffL;
+        return doubleToInt32(num) & MAX_UINT;
     }
 
     /**
@@ -702,10 +698,22 @@
      * @return a uint16
      */
     public static int toUint16(final double num) {
-        if (Double.isInfinite(num)) {
+        return ((int)doubleToInt32(num)) & 0xffff;
+    }
+
+    private static long doubleToInt32(final double num) {
+        final int exponent = Math.getExponent(num);
+        if (exponent < 31) {
+            return (long) num;  // Fits into 32 bits
+        }
+        if (exponent >= 84) {
+            // Either infinite or NaN or so large that shift / modulo will produce 0
+            // (52 bit mantissa + 32 bit target width).
             return 0;
         }
-        return ((int)(long)num) & 0xffff;
+        // This is rather slow and could probably be sped up using bit-fiddling.
+        final double d = (num >= 0) ? Math.floor(num) : Math.ceil(num);
+        return (long)(d % INT32_LIMIT);
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java	Thu May 16 11:47:51 2013 +0100
@@ -170,7 +170,7 @@
         Class<?> javaClass = null;
         try {
             javaClass = context.findClass(fullName);
-        } catch (final ClassNotFoundException e) {
+        } catch (final NoClassDefFoundError | ClassNotFoundException e) {
             //ignored
         }
 
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java	Thu May 16 11:47:51 2013 +0100
@@ -25,20 +25,20 @@
 
 package jdk.nashorn.internal.runtime;
 
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * Helper class to manage property listeners and notification.
  */
 public class PropertyListenerManager implements PropertyListener {
 
+    /** property listeners for this object. */
+    private Map<PropertyListener,Boolean> listeners;
+
     // These counters are updated in debug mode
     private static int listenersAdded;
     private static int listenersRemoved;
-    private static int listenersDead;
 
     /**
      * @return the listenersAdded
@@ -54,16 +54,6 @@
         return listenersRemoved;
     }
 
-    /**
-     * @return the listenersDead
-     */
-    public static int getListenersDead() {
-        return listenersDead;
-    }
-
-    /** property listeners for this object. */
-    private List<WeakReference<PropertyListener>> listeners;
-
     // Property listener management methods
 
     /**
@@ -73,12 +63,13 @@
      */
     public final void addPropertyListener(final PropertyListener listener) {
         if (listeners == null) {
-            listeners = new ArrayList<>();
+            listeners = new WeakHashMap<>();
         }
+
         if (Context.DEBUG) {
             listenersAdded++;
         }
-        listeners.add(new WeakReference<>(listener));
+        listeners.put(listener, Boolean.TRUE);
     }
 
     /**
@@ -88,15 +79,10 @@
      */
     public final void removePropertyListener(final PropertyListener listener) {
         if (listeners != null) {
-            final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
-            while (iter.hasNext()) {
-                if (iter.next().get() == listener) {
-                    if (Context.DEBUG) {
-                        listenersRemoved++;
-                    }
-                    iter.remove();
-                }
+            if (Context.DEBUG) {
+                listenersRemoved++;
             }
+            listeners.remove(listener);
         }
     }
 
@@ -108,18 +94,8 @@
      */
     protected final void notifyPropertyAdded(final ScriptObject object, final Property prop) {
         if (listeners != null) {
-            final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
-            while (iter.hasNext()) {
-                final WeakReference<PropertyListener> weakRef = iter.next();
-                final PropertyListener listener = weakRef.get();
-                if (listener == null) {
-                    if (Context.DEBUG) {
-                        listenersDead++;
-                    }
-                    iter.remove();
-                } else {
-                    listener.propertyAdded(object, prop);
-                }
+            for (PropertyListener listener : listeners.keySet()) {
+                listener.propertyAdded(object, prop);
             }
         }
     }
@@ -132,18 +108,8 @@
      */
     protected final void notifyPropertyDeleted(final ScriptObject object, final Property prop) {
         if (listeners != null) {
-            final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
-            while (iter.hasNext()) {
-                final WeakReference<PropertyListener> weakRef = iter.next();
-                final PropertyListener listener = weakRef.get();
-                if (listener == null) {
-                    if (Context.DEBUG) {
-                        listenersDead++;
-                    }
-                    iter.remove();
-                } else {
-                    listener.propertyDeleted(object, prop);
-                }
+            for (PropertyListener listener : listeners.keySet()) {
+                listener.propertyDeleted(object, prop);
             }
         }
     }
@@ -157,18 +123,8 @@
      */
     protected final void notifyPropertyModified(final ScriptObject object, final Property oldProp, final Property newProp) {
         if (listeners != null) {
-            final Iterator<WeakReference<PropertyListener>> iter = listeners.iterator();
-            while (iter.hasNext()) {
-                final WeakReference<PropertyListener> weakRef = iter.next();
-                final PropertyListener listener = weakRef.get();
-                if (listener == null) {
-                    if (Context.DEBUG) {
-                        listenersDead++;
-                    }
-                    iter.remove();
-                } else {
-                    listener.propertyModified(object, oldProp, newProp);
-                }
+            for (PropertyListener listener : listeners.keySet()) {
+                listener.propertyModified(object, oldProp, newProp);
             }
         }
     }
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu May 16 11:47:51 2013 +0100
@@ -25,10 +25,11 @@
 
 package jdk.nashorn.internal.runtime;
 
+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.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.FunctionSignature;
@@ -37,8 +38,6 @@
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
 /**
  * This is a subclass that represents a script function that may be regenerated,
  * for example with specialization based on call site types, or lazily generated.
@@ -47,7 +46,7 @@
  */
 public final class RecompilableScriptFunctionData extends ScriptFunctionData {
 
-    private final FunctionNode functionNode;
+    private FunctionNode functionNode;
     private final PropertyMap  allocatorMap;
     private final CodeInstaller<ScriptEnvironment> installer;
     private final String allocatorClassName;
@@ -70,7 +69,7 @@
                 "" :
                 functionNode.getIdent().getName(),
               functionNode.getParameters().size(),
-              functionNode.isStrictMode(),
+              functionNode.isStrict(),
               false,
               true);
 
@@ -129,7 +128,7 @@
 
     private void ensureHasAllocator() throws ClassNotFoundException {
         if (allocator == null && allocatorClassName != null) {
-            this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.tag(), MH.type(ScriptObject.class, PropertyMap.class));
+            this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.symbolName(), MH.type(ScriptObject.class, PropertyMap.class));
         }
     }
 
@@ -148,8 +147,11 @@
          // therefore, currently method specialization is disabled. TODO
 
          if (functionNode.isLazy()) {
-             Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '" + functionNode.getName() + "'");
-             new Compiler(installer, functionNode).compile().install();
+             Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'");
+             final Compiler compiler = new Compiler(installer, functionNode);
+             functionNode = compiler.compile();
+             assert !functionNode.isLazy();
+             compiler.install();
 
              // 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
@@ -159,7 +161,7 @@
          // we can't get here unless we have bytecode, either from eager compilation or from
          // running a lazy compile on the lines above
 
-         assert functionNode.hasState(CompilationState.INSTALLED);
+         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
          code.add(
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java	Thu May 16 11:47:51 2013 +0100
@@ -82,6 +82,36 @@
     /** Show full Nashorn version */
     public final boolean _fullversion;
 
+    /** Launch using as fx application */
+    public final boolean _fx;
+
+    /**
+     * Behavior when encountering a function declaration in a lexical context where only statements are acceptable
+     * (function declarations are source elements, but not statements).
+     */
+    public enum FunctionStatementBehavior {
+        /**
+         * Accept the function declaration silently and treat it as if it were a function expression assigned to a local
+         * variable.
+         */
+        ACCEPT,
+        /**
+         * Log a parser warning, but accept the function declaration and treat it as if it were a function expression
+         * assigned to a local variable.
+         */
+        WARNING,
+        /**
+         * Raise a {@code SyntaxError}.
+         */
+        ERROR
+    }
+
+    /**
+     * Behavior when encountering a function declaration in a lexical context where only statements are acceptable
+     * (function declarations are source elements, but not statements).
+     */
+    public final FunctionStatementBehavior _function_statement;
+
     /** Should lazy compilation take place */
     public final boolean _lazy_compilation;
 
@@ -158,6 +188,14 @@
         _early_lvalue_error   = options.getBoolean("early.lvalue.error");
         _empty_statements     = options.getBoolean("empty.statements");
         _fullversion          = options.getBoolean("fullversion");
+        if(options.getBoolean("function.statement.error")) {
+            _function_statement = FunctionStatementBehavior.ERROR;
+        } else if(options.getBoolean("function.statement.warning")) {
+            _function_statement = FunctionStatementBehavior.WARNING;
+        } else {
+            _function_statement = FunctionStatementBehavior.ACCEPT;
+        }
+        _fx                   = options.getBoolean("fx");
         _lazy_compilation     = options.getBoolean("lazy.compilation");
         _loader_per_compile   = options.getBoolean("loader.per.compile");
         _no_syntax_extensions = options.getBoolean("no.syntax.extensions");
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu May 16 11:47:51 2013 +0100
@@ -71,9 +71,6 @@
 
     private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
 
-    /** Reference to constructor prototype. */
-    protected Object prototype;
-
     /** The parent scope. */
     private final ScriptObject scope;
 
@@ -221,6 +218,7 @@
         final ScriptObject object = data.allocate();
 
         if (object != null) {
+            Object prototype = getPrototype();
             if (prototype instanceof ScriptObject) {
                 object.setProto((ScriptObject)prototype);
             }
@@ -282,24 +280,18 @@
      * Get the prototype object for this function
      * @return prototype
      */
-    public final Object getPrototype() {
-        return prototype;
-    }
+    public abstract Object getPrototype();
 
     /**
      * Set the prototype object for this function
      * @param prototype new prototype object
-     * @return the prototype parameter
      */
-    public final Object setPrototype(final Object prototype) {
-        this.prototype = prototype;
-        return prototype;
-    }
+    public abstract void setPrototype(Object prototype);
 
     /**
      * Return the most appropriate invoke handle if there are specializations
      * @param type most specific method type to look for invocation with
-     * @param callsite args for trampoline invocation
+     * @param args args for trampoline invocation
      * @return invoke method handle
      */
     private MethodHandle getBestInvoker(final MethodType type, final Object[] args) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu May 16 11:47:51 2013 +0100
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
@@ -39,7 +40,6 @@
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -61,12 +61,13 @@
 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
+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.runtime.arrays.ArrayData;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
-import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.lookup.MethodHandleFactory;
+import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
 import jdk.nashorn.internal.runtime.linker.NashornGuards;
 
@@ -901,7 +902,7 @@
         final MethodHandle getter = find.getGetter(int.class);
         if (getter != null) {
             try {
-                return (int)getter.invokeExact((Object)find.getOwner());
+                return (int)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -916,7 +917,7 @@
         final MethodHandle getter = find.getGetter(long.class);
         if (getter != null) {
             try {
-                return (long)getter.invokeExact((Object)find.getOwner());
+                return (long)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -931,7 +932,7 @@
         final MethodHandle getter = find.getGetter(double.class);
         if (getter != null) {
             try {
-                return (double)getter.invokeExact((Object)find.getOwner());
+                return (double)getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -953,7 +954,7 @@
         final MethodHandle getter = find.getGetter(Object.class);
         if (getter != null) {
             try {
-                return getter.invokeExact((Object)find.getOwner());
+                return getter.invokeExact((Object)find.getGetterReceiver());
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
@@ -1679,12 +1680,7 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
-        final String name = desc.getNameToken(2);
-
-        if (request.isCallSiteUnstable()) {
-            return findMegaMorphicGetMethod(desc, name);
-        }
-
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         final FindProperty find = findProperty(name, true);
 
         MethodHandle methodHandle;
@@ -1700,6 +1696,10 @@
             throw new AssertionError(); // never invoked with any other operation
         }
 
+        if (request.isCallSiteUnstable()) {
+            return findMegaMorphicGetMethod(desc, name);
+        }
+
         final Class<?> returnType = desc.getMethodType().returnType();
         final Property property = find.getProperty();
         methodHandle = find.getGetter(returnType);
@@ -1727,7 +1727,9 @@
     }
 
     private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name) {
-        final GuardedInvocation inv = findGetIndexMethod(desc.getMethodType().insertParameterTypes(1, Object.class));
+        final MethodType mhType = desc.getMethodType().insertParameterTypes(1, Object.class);
+        final GuardedInvocation inv = findGetIndexMethod(mhType);
+
         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
     }
 
@@ -1890,8 +1892,8 @@
     }
 
     private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
-        final GuardedInvocation inv = findSetIndexMethod(desc.getMethodType().insertParameterTypes(1, Object.class),
-                NashornCallSiteDescriptor.isStrict(desc));
+        final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
+        final GuardedInvocation inv = findSetIndexMethod(type, NashornCallSiteDescriptor.isStrict(desc));
         return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
     }
 
@@ -1949,7 +1951,7 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
-        final String name = desc.getNameToken(2);
+        final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
         final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
         final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
 
@@ -1973,6 +1975,24 @@
 
         return createEmptyGetter(desc, name);
     }
+    /**
+     * Invoke fall back if a property is not found.
+     * @param name Name of property.
+     * @return Result from call.
+     */
+    private Object invokeNoSuchProperty(final String name) {
+        final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+
+        if (find != null) {
+            final Object func = getObjectValue(find);
+
+            if (func instanceof ScriptFunction) {
+                return ScriptRuntime.apply((ScriptFunction)func, this, name);
+            }
+        }
+
+        return UNDEFINED;
+    }
 
     private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
         return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), getMap().getProtoGetSwitchPoint(name), NashornGuards.getMapGuard(getMap()));
@@ -2120,8 +2140,11 @@
      *
      * Make sure arguments are paired correctly.
      * @param methodHandle MethodHandle to adjust.
-     * @param callType     MethodType of caller.
-     * @param callerVarArg true if the caller is vararg, false otherwise, null if it should be inferred.
+     * @param callType     MethodType of the call site.
+     * @param callerVarArg true if the caller is vararg, false otherwise, null if it should be inferred from the
+     * {@code callType}; basically, if the last parameter type of the call site is an array, it'll be considered a
+     * variable arity call site. These are ordinarily rare; Nashorn code generator creates variable arity call sites
+     * when the call has more than {@link LinkerCallSite#ARGLIMIT} parameters.
      *
      * @return method handle with adjusted arguments
      */
@@ -2136,7 +2159,7 @@
         final int callCount      = callType.parameterCount();
 
         final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
-        final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 1 &&
+        final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 0 &&
                 callType.parameterType(callCount - 1).isArray());
 
         if (callCount < parameterCount) {
@@ -2239,310 +2262,314 @@
            setArray(getArray().shrink(newLength));
            getArray().setLength(newLength);
        }
-   }
+    }
+
+    private int getInt(final int index, final String key) {
+        if (isValidArrayIndex(index)) {
+             for (ScriptObject object = this; ; ) {
+                final FindProperty find = object.findProperty(key, false, false, this);
+
+                if (find != null) {
+                    return getIntValue(find);
+                }
+
+                if ((object = object.getProto()) == null) {
+                    break;
+                }
+
+                final ArrayData array = object.getArray();
+
+                if (array.has(index)) {
+                    return array.getInt(index);
+                }
+           }
+        } else {
+            final FindProperty find = findProperty(key, true);
+
+            if (find != null) {
+                return getIntValue(find);
+            }
+        }
+
+        return JSType.toInt32(invokeNoSuchProperty(key));
+    }
 
     @Override
     public int getInt(final Object key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getInt(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(index, convertKey(key));
     }
 
     @Override
     public int getInt(final double key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getInt(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(index, convertKey(key));
     }
 
     @Override
     public int getInt(final long key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getInt(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return getInt(index, convertKey(key));
     }
 
     @Override
     public int getInt(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getInt(index);
+        final ArrayData array = getArray();
+
+        if (array.has(key)) {
+            return array.getInt(key);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getIntValue(find);
+        return getInt(key, convertKey(key));
+    }
+
+    private long getLong(final int index, final String key) {
+        if (isValidArrayIndex(index)) {
+            for (ScriptObject object = this; ; ) {
+                final FindProperty find = object.findProperty(key, false, false, this);
+
+                if (find != null) {
+                    return getLongValue(find);
+                }
+
+                if ((object = object.getProto()) == null) {
+                    break;
+                }
+
+                final ArrayData array = object.getArray();
+
+                if (array.has(index)) {
+                    return array.getLong(index);
+                }
+           }
+        } else {
+            final FindProperty find = findProperty(key, true);
+
+            if (find != null) {
+                return getLongValue(find);
+            }
         }
 
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getInt(key) : 0;
+        return JSType.toLong(invokeNoSuchProperty(key));
     }
 
     @Override
     public long getLong(final Object key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getLong(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(index, convertKey(key));
     }
 
     @Override
     public long getLong(final double key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getLong(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(index, convertKey(key));
     }
 
     @Override
     public long getLong(final long key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getLong(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return getLong(index, convertKey(key));
     }
 
     @Override
     public long getLong(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getLong(index);
+        final ArrayData array = getArray();
+
+        if (array.has(key)) {
+            return array.getLong(key);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getLongValue(find);
+        return getLong(key, convertKey(key));
+    }
+
+    private double getDouble(final int index, final String key) {
+        if (isValidArrayIndex(index)) {
+            for (ScriptObject object = this; ; ) {
+                final FindProperty find = object.findProperty(key, false, false, this);
+
+                if (find != null) {
+                    return getDoubleValue(find);
+                }
+
+                if ((object = object.getProto()) == null) {
+                    break;
+                }
+
+                final ArrayData array = object.getArray();
+
+                if (array.has(index)) {
+                    return array.getDouble(index);
+                }
+           }
+        } else {
+            final FindProperty find = findProperty(key, true);
+
+            if (find != null) {
+                return getDoubleValue(find);
+            }
         }
 
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getLong(key) : 0L;
+        return JSType.toNumber(invokeNoSuchProperty(key));
     }
 
     @Override
     public double getDouble(final Object key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getDouble(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(index, convertKey(key));
     }
 
     @Override
     public double getDouble(final double key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getDouble(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(index, convertKey(key));
     }
 
     @Override
     public double getDouble(final long key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getDouble(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return getDouble(index, convertKey(key));
     }
 
     @Override
     public double getDouble(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getDouble(index);
+        final ArrayData array = getArray();
+
+        if (array.has(key)) {
+            return array.getDouble(key);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getDoubleValue(find);
+        return getDouble(key, convertKey(key));
+    }
+
+    private Object get(final int index, final String key) {
+        if (isValidArrayIndex(index)) {
+            for (ScriptObject object = this; ; ) {
+                final FindProperty find = object.findProperty(key, false, false, this);
+
+                if (find != null) {
+                    return getObjectValue(find);
+                }
+
+                if ((object = object.getProto()) == null) {
+                    break;
+                }
+
+                final ArrayData array = object.getArray();
+
+                if (array.has(index)) {
+                    return array.getObject(index);
+                }
+            }
+        } else {
+            final FindProperty find = findProperty(key, true);
+
+            if (find != null) {
+                return getObjectValue(find);
+            }
         }
 
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.getDouble(key) : Double.NaN;
+        return invokeNoSuchProperty(key);
     }
 
     @Override
     public Object get(final Object key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getObject(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(index, convertKey(key));
     }
 
     @Override
     public Object get(final double key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getObject(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(index, convertKey(key));
     }
 
     @Override
     public Object get(final long key) {
         final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
+        final ArrayData array = getArray();
+
+        if (array.has(index)) {
+            return array.getObject(index);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(index, convertKey(key));
     }
 
     @Override
     public Object get(final int key) {
-        final int index = getArrayIndexNoThrow(key);
-
-        if (getArray().has(index)) {
-            return getArray().getObject(index);
+        final ArrayData array = getArray();
+
+        if (array.has(key)) {
+            return array.getObject(key);
         }
 
-        final FindProperty find = findProperty(convertKey(key), false);
-
-        if (find != null) {
-            return getObjectValue(find);
-        }
-
-        final ScriptObject proto = this.getProto();
-
-        return proto != null ? proto.get(key) : UNDEFINED;
+        return get(key, convertKey(key));
     }
 
     /**
@@ -2554,7 +2581,7 @@
      */
     private void doesNotHave(final int index, final Object value, final boolean strict) {
         final long oldLength = getArray().length();
-        final long longIndex = index & 0xffff_ffffL;
+        final long longIndex = index & JSType.MAX_UINT;
 
         if (!getArray().has(index)) {
             final String key = convertKey(longIndex);
@@ -2613,8 +2640,6 @@
             f = null;
         }
 
-        MethodHandle setter;
-
         if (f != null) {
             if (!f.getProperty().isWritable()) {
                 if (strict) {
@@ -2624,9 +2649,9 @@
                 return;
             }
 
-            setter = f.getSetter(Object.class, strict); //TODO specfields
             try {
-                setter.invokeExact((Object)f.getOwner(), value);
+                final MethodHandle setter = f.getSetter(Object.class, strict); //TODO specfields
+                setter.invokeExact((Object)f.getSetterReceiver(), value);
             } catch (final Error|RuntimeException e) {
                 throw e;
             } catch (final Throwable e) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/StructureLoader.java	Thu May 16 11:47:51 2013 +0100
@@ -47,7 +47,7 @@
  *
  */
 final class StructureLoader extends NashornLoader {
-    private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.tag();
+    private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.symbolName();
     private static final String OBJECTS_PACKAGE_EXTERNAL  = binaryName(OBJECTS_PACKAGE);
 
     /**
@@ -110,7 +110,7 @@
     @Override
     protected Class<?> findClass(final String name) throws ClassNotFoundException {
         if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) {
-            final int start = name.indexOf(JS_OBJECT_PREFIX.tag()) + JS_OBJECT_PREFIX.tag().length();
+            final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length();
             return generateClass(name, name.substring(start, name.length()));
         }
         return super.findClass(name);
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java	Thu May 16 11:47:51 2013 +0100
@@ -232,11 +232,18 @@
         return (Scope) proto;
     }
 
+    private static GuardedInvocation fixReceiverType(final GuardedInvocation link, final MethodHandle filter) {
+        // The receiver may be an Object or a ScriptObject.
+        final MethodType invType = link.getInvocation().type();
+        final MethodType newInvType = invType.changeParameterType(0, filter.type().returnType());
+        return link.asType(newInvType);
+    }
+
     private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
         // If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
         // expression.
         if(!"getMethod".equals(desc.getFirstOperator())) {
-            return link.filterArguments(0, WITHEXPRESSIONFILTER);
+            return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
         }
 
         final MethodHandle linkInvocation = link.getInvocation();
@@ -252,7 +259,8 @@
     }
 
     private static GuardedInvocation fixScopeCallSite(final GuardedInvocation link) {
-        return link.replaceMethods(filter(link.getInvocation(), WITHSCOPEFILTER), filterGuard(link, WITHSCOPEFILTER));
+        final GuardedInvocation newLink = fixReceiverType(link, WITHSCOPEFILTER);
+        return link.replaceMethods(filter(newLink.getInvocation(), WITHSCOPEFILTER), filterGuard(newLink, WITHSCOPEFILTER));
     }
 
     private static MethodHandle filterGuard(final GuardedInvocation link, final MethodHandle filter) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java	Thu May 16 11:47:51 2013 +0100
@@ -84,7 +84,9 @@
      * @return valid array index, or negative value if not valid
      */
     public static int getArrayIndexNoThrow(final Object key) {
-        if (key instanceof Number) {
+        if (key instanceof Integer) {
+            return getArrayIndexNoThrow(((Integer)key).intValue());
+        } else if (key instanceof Number) {
             return getArrayIndexNoThrow(((Number)key).doubleValue());
         } else if (key instanceof String) {
             return (int)fromString((String)key);
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java	Thu May 16 11:47:51 2013 +0100
@@ -66,8 +66,7 @@
             bumpIndex();
         }
 
-        // special case - balk at iterating to infinity or MAX_UINT
-        return (length != JSType.MAX_UINT) && indexInArray();
+        return indexInArray();
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java	Thu May 16 11:47:51 2013 +0100
@@ -273,7 +273,7 @@
     }
 
     private static Long indexToKey(final int index) {
-        return Long.valueOf(index & 0xffff_ffffL);
+        return Long.valueOf(index & JSType.MAX_UINT);
     }
 
     @Override
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java	Thu May 16 11:47:51 2013 +0100
@@ -185,4 +185,4 @@
         }
         return classesAndLoaders.keySet();
     }
-}
\ No newline at end of file
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java	Thu May 16 11:47:51 2013 +0100
@@ -127,9 +127,9 @@
     private static final Type METHOD_TYPE_TYPE = Type.getType(MethodType.class);
     private static final Type METHOD_HANDLE_TYPE = Type.getType(MethodHandle.class);
     private static final String GET_HANDLE_OBJECT_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
-            OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE);
+            OBJECT_TYPE, STRING_TYPE, METHOD_TYPE_TYPE);
     private static final String GET_HANDLE_FUNCTION_DESCRIPTOR = Type.getMethodDescriptor(METHOD_HANDLE_TYPE,
-            SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE, Type.BOOLEAN_TYPE);
+            SCRIPT_FUNCTION_TYPE, METHOD_TYPE_TYPE);
     private static final String GET_CLASS_INITIALIZER_DESCRIPTOR = Type.getMethodDescriptor(SCRIPT_OBJECT_TYPE);
     private static final Type RUNTIME_EXCEPTION_TYPE = Type.getType(RuntimeException.class);
     private static final Type THROWABLE_TYPE = Type.getType(Throwable.class);
@@ -315,7 +315,6 @@
             mv.dup();
             mv.aconst(mi.getName());
             mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
-            mv.iconst(mi.method.isVarArgs() ? 1 : 0);
             mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", GET_HANDLE_OBJECT_DESCRIPTOR);
             mv.putstatic(generatedClassName, mi.methodHandleClassFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
         }
@@ -459,7 +458,6 @@
                     mv.aconst(mi.getName());
                 }
                 mv.aconst(Type.getMethodType(mi.type.toMethodDescriptorString()));
-                mv.iconst(mi.method.isVarArgs() ? 1 : 0);
                 mv.invokestatic(SERVICES_CLASS_TYPE_NAME, "getHandle", getHandleDescriptor);
             }
             mv.putfield(generatedClassName, mi.methodHandleInstanceFieldName, METHOD_HANDLE_TYPE_DESCRIPTOR);
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterServices.java	Thu May 16 11:47:51 2013 +0100
@@ -50,12 +50,11 @@
      * handles for their abstract method implementations.
      * @param fn the script function
      * @param type the method type it has to conform to
-     * @param varArg if the Java method for which the function is being adapted is a variable arity method
      * @return the appropriately adapted method handle for invoking the script function.
      */
-    public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type, final boolean varArg) {
+    public static MethodHandle getHandle(final ScriptFunction fn, final MethodType type) {
         // JS "this" will be null for SAMs
-        return adaptHandle(fn.getBoundInvokeHandle(null), type, varArg);
+        return adaptHandle(fn.getBoundInvokeHandle(null), type);
     }
 
     /**
@@ -66,12 +65,11 @@
      * @param obj the script obj
      * @param name the name of the property that contains the function
      * @param type the method type it has to conform to
-     * @param varArg if the Java method for which the function is being adapted is a variable arity method
      * @return the appropriately adapted method handle for invoking the script function, or null if the value of the
      * property is either null or undefined, or "toString" was requested as the name, but the object doesn't directly
      * define it but just inherits it through prototype.
      */
-    public static MethodHandle getHandle(final Object obj, final String name, final MethodType type, final boolean varArg) {
+    public static MethodHandle getHandle(final Object obj, final String name, final MethodType type) {
         if (! (obj instanceof ScriptObject)) {
             throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
         }
@@ -84,7 +82,7 @@
 
         final Object fnObj = sobj.get(name);
         if (fnObj instanceof ScriptFunction) {
-            return adaptHandle(((ScriptFunction)fnObj).getBoundInvokeHandle(sobj), type, varArg);
+            return adaptHandle(((ScriptFunction)fnObj).getBoundInvokeHandle(sobj), type);
         } else if(fnObj == null || fnObj instanceof Undefined) {
             return null;
         } else {
@@ -108,7 +106,7 @@
         classOverrides.set(overrides);
     }
 
-    private static MethodHandle adaptHandle(final MethodHandle handle, final MethodType type, final boolean varArg) {
-        return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(handle, type, varArg), type);
+    private static MethodHandle adaptHandle(final MethodHandle handle, final MethodType type) {
+        return Bootstrap.getLinkerServices().asType(ScriptObject.pairArguments(handle, type, false), type);
     }
 }
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Thu May 16 11:47:51 2013 +0100
@@ -43,9 +43,8 @@
     public static final int CALLSITE_SCOPE                = 0x01;
     /** Flags that the call site is in code that uses ECMAScript strict mode. */
     public static final int CALLSITE_STRICT               = 0x02;
-    /** Flags that a property getter or setter call site references a scope variable that is not in the global scope
-     * (it is in a function lexical scope), and the function's scope object class is fixed and known in advance. Such
-     * getters and setters can often be linked more optimally using these assumptions. */
+    /** Flags that a property getter or setter call site references a scope variable that is located at a known distance
+     * in the scope chain. Such getters and setters can often be linked more optimally using these assumptions. */
     public static final int CALLSITE_FAST_SCOPE    = 0x400;
 
     /** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
--- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java	Thu May 16 11:47:51 2013 +0100
@@ -243,7 +243,13 @@
      */
     public String getString(final String key) {
         final Option<?> option = get(key);
-        return option != null ? (String)option.getValue() : null;
+        if(option != null) {
+            final String value = (String)option.getValue();
+            if(value != null) {
+                return value.intern();
+            }
+        }
+        return null;
     }
 
     /**
--- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Parser.java	Thu May 16 11:47:51 2013 +0100
@@ -287,7 +287,10 @@
 
                     if (syntax.allowDoubleRangeOpInCC()) {
                         env.ccEscWarn("-");
-                        parseCharClassSbChar(cc, arg); // goto sb_char /* [0-9-a] is allowed as [0-9\-a] */
+                        arg.inType = CCVALTYPE.SB;
+                        arg.v = '-';
+                        arg.vIsRaw = false;
+                        parseCharClassValEntry2(cc, arg); // goto val_entry2 /* [0-9-a] is allowed as [0-9\-a] */
                         break;
                     }
                     newSyntaxException(ERR_UNMATCHED_RANGE_SPECIFIER_IN_CHAR_CLASS);
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties	Thu May 16 11:47:51 2013 +0100
@@ -144,6 +144,26 @@
     desc="Print full version info of Nashorn." \
 }
 
+nashorn.option.function.statement.error= {                                    \
+    name="--function-statement-error",                                        \
+    desc="Report an error when function declaration is used as a statement.", \
+    is_undocumented=true,                                                     \
+    default=false                                                             \
+}
+
+nashorn.option.function.statement.warning = {                      \
+    name="--function-statement-warning",                           \
+    desc="Warn when function declaration is used as a statement.", \
+    is_undocumented=true,                                          \
+    default=false                                                  \
+}
+
+nashorn.option.fx = {                           \
+    name="-fx",                                 \
+    desc="Launch script as an fx application.", \
+    default=false                               \
+}
+
 nashorn.option.log = {                                                       \
     name="--log",                                                            \
     is_undocumented=true,                                                    \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/base.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+Scene                                  = Java.type("javafx.scene.Scene");
+Group                                  = Java.type("javafx.scene.Group");
+Stage                                  = Java.type("javafx.stage.Stage");
+
+Binding                                = Java.type("javafx.beans.binding.Binding");
+Bindings                               = Java.type("javafx.beans.binding.Bindings");
+BooleanBinding                         = Java.type("javafx.beans.binding.BooleanBinding");
+BooleanExpression                      = Java.type("javafx.beans.binding.BooleanExpression");
+DoubleBinding                          = Java.type("javafx.beans.binding.DoubleBinding");
+DoubleExpression                       = Java.type("javafx.beans.binding.DoubleExpression");
+FloatBinding                           = Java.type("javafx.beans.binding.FloatBinding");
+FloatExpression                        = Java.type("javafx.beans.binding.FloatExpression");
+IntegerBinding                         = Java.type("javafx.beans.binding.IntegerBinding");
+IntegerExpression                      = Java.type("javafx.beans.binding.IntegerExpression");
+ListBinding                            = Java.type("javafx.beans.binding.ListBinding");
+ListExpression                         = Java.type("javafx.beans.binding.ListExpression");
+LongBinding                            = Java.type("javafx.beans.binding.LongBinding");
+LongExpression                         = Java.type("javafx.beans.binding.LongExpression");
+MapBinding                             = Java.type("javafx.beans.binding.MapBinding");
+MapExpression                          = Java.type("javafx.beans.binding.MapExpression");
+NumberBinding                          = Java.type("javafx.beans.binding.NumberBinding");
+NumberExpression                       = Java.type("javafx.beans.binding.NumberExpression");
+NumberExpressionBase                   = Java.type("javafx.beans.binding.NumberExpressionBase");
+ObjectBinding                          = Java.type("javafx.beans.binding.ObjectBinding");
+ObjectExpression                       = Java.type("javafx.beans.binding.ObjectExpression");
+SetBinding                             = Java.type("javafx.beans.binding.SetBinding");
+SetExpression                          = Java.type("javafx.beans.binding.SetExpression");
+StringBinding                          = Java.type("javafx.beans.binding.StringBinding");
+StringExpression                       = Java.type("javafx.beans.binding.StringExpression");
+When                                   = Java.type("javafx.beans.binding.When");
+DefaultProperty                        = Java.type("javafx.beans.DefaultProperty");
+InvalidationListener                   = Java.type("javafx.beans.InvalidationListener");
+Observable                             = Java.type("javafx.beans.Observable");
+JavaBeanBooleanProperty                = Java.type("javafx.beans.property.adapter.JavaBeanBooleanProperty");
+JavaBeanBooleanPropertyBuilder         = Java.type("javafx.beans.property.adapter.JavaBeanBooleanPropertyBuilder");
+JavaBeanDoubleProperty                 = Java.type("javafx.beans.property.adapter.JavaBeanDoubleProperty");
+JavaBeanDoublePropertyBuilder          = Java.type("javafx.beans.property.adapter.JavaBeanDoublePropertyBuilder");
+JavaBeanFloatProperty                  = Java.type("javafx.beans.property.adapter.JavaBeanFloatProperty");
+JavaBeanFloatPropertyBuilder           = Java.type("javafx.beans.property.adapter.JavaBeanFloatPropertyBuilder");
+JavaBeanIntegerProperty                = Java.type("javafx.beans.property.adapter.JavaBeanIntegerProperty");
+JavaBeanIntegerPropertyBuilder         = Java.type("javafx.beans.property.adapter.JavaBeanIntegerPropertyBuilder");
+JavaBeanLongProperty                   = Java.type("javafx.beans.property.adapter.JavaBeanLongProperty");
+JavaBeanLongPropertyBuilder            = Java.type("javafx.beans.property.adapter.JavaBeanLongPropertyBuilder");
+JavaBeanObjectProperty                 = Java.type("javafx.beans.property.adapter.JavaBeanObjectProperty");
+JavaBeanObjectPropertyBuilder          = Java.type("javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder");
+JavaBeanProperty                       = Java.type("javafx.beans.property.adapter.JavaBeanProperty");
+JavaBeanStringProperty                 = Java.type("javafx.beans.property.adapter.JavaBeanStringProperty");
+JavaBeanStringPropertyBuilder          = Java.type("javafx.beans.property.adapter.JavaBeanStringPropertyBuilder");
+ReadOnlyJavaBeanBooleanProperty        = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanBooleanProperty");
+ReadOnlyJavaBeanBooleanPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanBooleanPropertyBuilder");
+ReadOnlyJavaBeanDoubleProperty         = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanDoubleProperty");
+ReadOnlyJavaBeanDoublePropertyBuilder  = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanDoublePropertyBuilder");
+ReadOnlyJavaBeanFloatProperty          = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanFloatProperty");
+ReadOnlyJavaBeanFloatPropertyBuilder   = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanFloatPropertyBuilder");
+ReadOnlyJavaBeanIntegerProperty        = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanIntegerProperty");
+ReadOnlyJavaBeanIntegerPropertyBuilder = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanIntegerPropertyBuilder");
+ReadOnlyJavaBeanLongProperty           = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanLongProperty");
+ReadOnlyJavaBeanLongPropertyBuilder    = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanLongPropertyBuilder");
+ReadOnlyJavaBeanObjectProperty         = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanObjectProperty");
+ReadOnlyJavaBeanObjectPropertyBuilder  = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanObjectPropertyBuilder");
+ReadOnlyJavaBeanProperty               = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanProperty");
+ReadOnlyJavaBeanStringProperty         = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanStringProperty");
+ReadOnlyJavaBeanStringPropertyBuilder  = Java.type("javafx.beans.property.adapter.ReadOnlyJavaBeanStringPropertyBuilder");
+BooleanProperty                        = Java.type("javafx.beans.property.BooleanProperty");
+BooleanPropertyBase                    = Java.type("javafx.beans.property.BooleanPropertyBase");
+DoubleProperty                         = Java.type("javafx.beans.property.DoubleProperty");
+DoublePropertyBase                     = Java.type("javafx.beans.property.DoublePropertyBase");
+FloatProperty                          = Java.type("javafx.beans.property.FloatProperty");
+FloatPropertyBase                      = Java.type("javafx.beans.property.FloatPropertyBase");
+IntegerProperty                        = Java.type("javafx.beans.property.IntegerProperty");
+IntegerPropertyBase                    = Java.type("javafx.beans.property.IntegerPropertyBase");
+ListProperty                           = Java.type("javafx.beans.property.ListProperty");
+ListPropertyBase                       = Java.type("javafx.beans.property.ListPropertyBase");
+LongProperty                           = Java.type("javafx.beans.property.LongProperty");
+LongPropertyBase                       = Java.type("javafx.beans.property.LongPropertyBase");
+MapProperty                            = Java.type("javafx.beans.property.MapProperty");
+MapPropertyBase                        = Java.type("javafx.beans.property.MapPropertyBase");
+ObjectProperty                         = Java.type("javafx.beans.property.ObjectProperty");
+ObjectPropertyBase                     = Java.type("javafx.beans.property.ObjectPropertyBase");
+Property                               = Java.type("javafx.beans.property.Property");
+ReadOnlyBooleanProperty                = Java.type("javafx.beans.property.ReadOnlyBooleanProperty");
+ReadOnlyBooleanPropertyBase            = Java.type("javafx.beans.property.ReadOnlyBooleanPropertyBase");
+ReadOnlyBooleanWrapper                 = Java.type("javafx.beans.property.ReadOnlyBooleanWrapper");
+ReadOnlyDoubleProperty                 = Java.type("javafx.beans.property.ReadOnlyDoubleProperty");
+ReadOnlyDoublePropertyBase             = Java.type("javafx.beans.property.ReadOnlyDoublePropertyBase");
+ReadOnlyDoubleWrapper                  = Java.type("javafx.beans.property.ReadOnlyDoubleWrapper");
+ReadOnlyFloatProperty                  = Java.type("javafx.beans.property.ReadOnlyFloatProperty");
+ReadOnlyFloatPropertyBase              = Java.type("javafx.beans.property.ReadOnlyFloatPropertyBase");
+ReadOnlyFloatWrapper                   = Java.type("javafx.beans.property.ReadOnlyFloatWrapper");
+ReadOnlyIntegerProperty                = Java.type("javafx.beans.property.ReadOnlyIntegerProperty");
+ReadOnlyIntegerPropertyBase            = Java.type("javafx.beans.property.ReadOnlyIntegerPropertyBase");
+ReadOnlyIntegerWrapper                 = Java.type("javafx.beans.property.ReadOnlyIntegerWrapper");
+ReadOnlyListProperty                   = Java.type("javafx.beans.property.ReadOnlyListProperty");
+ReadOnlyListPropertyBase               = Java.type("javafx.beans.property.ReadOnlyListPropertyBase");
+ReadOnlyListWrapper                    = Java.type("javafx.beans.property.ReadOnlyListWrapper");
+ReadOnlyLongProperty                   = Java.type("javafx.beans.property.ReadOnlyLongProperty");
+ReadOnlyLongPropertyBase               = Java.type("javafx.beans.property.ReadOnlyLongPropertyBase");
+ReadOnlyLongWrapper                    = Java.type("javafx.beans.property.ReadOnlyLongWrapper");
+ReadOnlyMapProperty                    = Java.type("javafx.beans.property.ReadOnlyMapProperty");
+ReadOnlyMapPropertyBase                = Java.type("javafx.beans.property.ReadOnlyMapPropertyBase");
+ReadOnlyMapWrapper                     = Java.type("javafx.beans.property.ReadOnlyMapWrapper");
+ReadOnlyObjectProperty                 = Java.type("javafx.beans.property.ReadOnlyObjectProperty");
+ReadOnlyObjectPropertyBase             = Java.type("javafx.beans.property.ReadOnlyObjectPropertyBase");
+ReadOnlyObjectWrapper                  = Java.type("javafx.beans.property.ReadOnlyObjectWrapper");
+ReadOnlyProperty                       = Java.type("javafx.beans.property.ReadOnlyProperty");
+ReadOnlySetProperty                    = Java.type("javafx.beans.property.ReadOnlySetProperty");
+ReadOnlySetPropertyBase                = Java.type("javafx.beans.property.ReadOnlySetPropertyBase");
+ReadOnlySetWrapper                     = Java.type("javafx.beans.property.ReadOnlySetWrapper");
+ReadOnlyStringProperty                 = Java.type("javafx.beans.property.ReadOnlyStringProperty");
+ReadOnlyStringPropertyBase             = Java.type("javafx.beans.property.ReadOnlyStringPropertyBase");
+ReadOnlyStringWrapper                  = Java.type("javafx.beans.property.ReadOnlyStringWrapper");
+SetProperty                            = Java.type("javafx.beans.property.SetProperty");
+SetPropertyBase                        = Java.type("javafx.beans.property.SetPropertyBase");
+SimpleBooleanProperty                  = Java.type("javafx.beans.property.SimpleBooleanProperty");
+SimpleDoubleProperty                   = Java.type("javafx.beans.property.SimpleDoubleProperty");
+SimpleFloatProperty                    = Java.type("javafx.beans.property.SimpleFloatProperty");
+SimpleIntegerProperty                  = Java.type("javafx.beans.property.SimpleIntegerProperty");
+SimpleListProperty                     = Java.type("javafx.beans.property.SimpleListProperty");
+SimpleLongProperty                     = Java.type("javafx.beans.property.SimpleLongProperty");
+SimpleMapProperty                      = Java.type("javafx.beans.property.SimpleMapProperty");
+SimpleObjectProperty                   = Java.type("javafx.beans.property.SimpleObjectProperty");
+SimpleSetProperty                      = Java.type("javafx.beans.property.SimpleSetProperty");
+SimpleStringProperty                   = Java.type("javafx.beans.property.SimpleStringProperty");
+StringProperty                         = Java.type("javafx.beans.property.StringProperty");
+StringPropertyBase                     = Java.type("javafx.beans.property.StringPropertyBase");
+ChangeListener                         = Java.type("javafx.beans.value.ChangeListener");
+ObservableBooleanValue                 = Java.type("javafx.beans.value.ObservableBooleanValue");
+ObservableDoubleValue                  = Java.type("javafx.beans.value.ObservableDoubleValue");
+ObservableFloatValue                   = Java.type("javafx.beans.value.ObservableFloatValue");
+ObservableIntegerValue                 = Java.type("javafx.beans.value.ObservableIntegerValue");
+ObservableListValue                    = Java.type("javafx.beans.value.ObservableListValue");
+ObservableLongValue                    = Java.type("javafx.beans.value.ObservableLongValue");
+ObservableMapValue                     = Java.type("javafx.beans.value.ObservableMapValue");
+ObservableNumberValue                  = Java.type("javafx.beans.value.ObservableNumberValue");
+ObservableObjectValue                  = Java.type("javafx.beans.value.ObservableObjectValue");
+ObservableSetValue                     = Java.type("javafx.beans.value.ObservableSetValue");
+ObservableStringValue                  = Java.type("javafx.beans.value.ObservableStringValue");
+ObservableValue                        = Java.type("javafx.beans.value.ObservableValue");
+ObservableValueBase                    = Java.type("javafx.beans.value.ObservableValueBase");
+WeakChangeListener                     = Java.type("javafx.beans.value.WeakChangeListener");
+WritableBooleanValue                   = Java.type("javafx.beans.value.WritableBooleanValue");
+WritableDoubleValue                    = Java.type("javafx.beans.value.WritableDoubleValue");
+WritableFloatValue                     = Java.type("javafx.beans.value.WritableFloatValue");
+WritableIntegerValue                   = Java.type("javafx.beans.value.WritableIntegerValue");
+WritableListValue                      = Java.type("javafx.beans.value.WritableListValue");
+WritableLongValue                      = Java.type("javafx.beans.value.WritableLongValue");
+WritableMapValue                       = Java.type("javafx.beans.value.WritableMapValue");
+WritableNumberValue                    = Java.type("javafx.beans.value.WritableNumberValue");
+WritableObjectValue                    = Java.type("javafx.beans.value.WritableObjectValue");
+WritableSetValue                       = Java.type("javafx.beans.value.WritableSetValue");
+WritableStringValue                    = Java.type("javafx.beans.value.WritableStringValue");
+WritableValue                          = Java.type("javafx.beans.value.WritableValue");
+WeakInvalidationListener               = Java.type("javafx.beans.WeakInvalidationListener");
+WeakListener                           = Java.type("javafx.beans.WeakListener");
+FXCollections                          = Java.type("javafx.collections.FXCollections");
+ListChangeListener                     = Java.type("javafx.collections.ListChangeListener");
+ListChangeListener$Change              = Java.type("javafx.collections.ListChangeListener$Change");
+MapChangeListener                      = Java.type("javafx.collections.MapChangeListener");
+MapChangeListener$Change               = Java.type("javafx.collections.MapChangeListener$Change");
+ModifiableObservableListBase           = Java.type("javafx.collections.ModifiableObservableListBase");
+ObservableList                         = Java.type("javafx.collections.ObservableList");
+ObservableListBase                     = Java.type("javafx.collections.ObservableListBase");
+ObservableMap                          = Java.type("javafx.collections.ObservableMap");
+ObservableSet                          = Java.type("javafx.collections.ObservableSet");
+SetChangeListener                      = Java.type("javafx.collections.SetChangeListener");
+SetChangeListener$Change               = Java.type("javafx.collections.SetChangeListener$Change");
+WeakListChangeListener                 = Java.type("javafx.collections.WeakListChangeListener");
+WeakMapChangeListener                  = Java.type("javafx.collections.WeakMapChangeListener");
+WeakSetChangeListener                  = Java.type("javafx.collections.WeakSetChangeListener");
+ActionEvent                            = Java.type("javafx.event.ActionEvent");
+Event                                  = Java.type("javafx.event.Event");
+EventDispatchChain                     = Java.type("javafx.event.EventDispatchChain");
+EventDispatcher                        = Java.type("javafx.event.EventDispatcher");
+EventHandler                           = Java.type("javafx.event.EventHandler");
+EventTarget                            = Java.type("javafx.event.EventTarget");
+EventType                              = Java.type("javafx.event.EventType");
+WeakEventHandler                       = Java.type("javafx.event.WeakEventHandler");
+Builder                                = Java.type("javafx.util.Builder");
+BuilderFactory                         = Java.type("javafx.util.BuilderFactory");
+Callback                               = Java.type("javafx.util.Callback");
+BigDecimalStringConverter              = Java.type("javafx.util.converter.BigDecimalStringConverter");
+BigIntegerStringConverter              = Java.type("javafx.util.converter.BigIntegerStringConverter");
+BooleanStringConverter                 = Java.type("javafx.util.converter.BooleanStringConverter");
+ByteStringConverter                    = Java.type("javafx.util.converter.ByteStringConverter");
+CharacterStringConverter               = Java.type("javafx.util.converter.CharacterStringConverter");
+CurrencyStringConverter                = Java.type("javafx.util.converter.CurrencyStringConverter");
+DateStringConverter                    = Java.type("javafx.util.converter.DateStringConverter");
+DateTimeStringConverter                = Java.type("javafx.util.converter.DateTimeStringConverter");
+DefaultStringConverter                 = Java.type("javafx.util.converter.DefaultStringConverter");
+DoubleStringConverter                  = Java.type("javafx.util.converter.DoubleStringConverter");
+FloatStringConverter                   = Java.type("javafx.util.converter.FloatStringConverter");
+FormatStringConverter                  = Java.type("javafx.util.converter.FormatStringConverter");
+IntegerStringConverter                 = Java.type("javafx.util.converter.IntegerStringConverter");
+LongStringConverter                    = Java.type("javafx.util.converter.LongStringConverter");
+NumberStringConverter                  = Java.type("javafx.util.converter.NumberStringConverter");
+PercentageStringConverter              = Java.type("javafx.util.converter.PercentageStringConverter");
+ShortStringConverter                   = Java.type("javafx.util.converter.ShortStringConverter");
+TimeStringConverter                    = Java.type("javafx.util.converter.TimeStringConverter");
+Duration                               = Java.type("javafx.util.Duration");
+Pair                                   = Java.type("javafx.util.Pair");
+StringConverter                        = Java.type("javafx.util.StringConverter");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/bootstrap.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+// Check for fx presence.
+if (typeof javafx.application.Application != "function") {
+    print("JavaFX is not available.");
+    exit(1);
+}
+
+// Extend the javafx.application.Application class overriding init, start and stop.
+com.sun.javafx.application.LauncherImpl.launchApplication((Java.extend(javafx.application.Application, {
+    // Overridden javafx.application.Application.init();
+    init: function() {
+        // Java FX packages and classes must be defined here because
+        // they may not be viable until launch time due to clinit ordering.
+
+        load("fx:base.js");
+    },
+
+    // Overridden javafx.application.Application.start(Stage stage);
+    start: function(stage) {
+        // Set up stage global.
+        $STAGE = stage;
+
+        // Load user FX scripts.
+        for each (var script in $SCRIPTS) {
+            load(script);
+        }
+
+        // Call the global init function if present.
+        if ($GLOBAL.init) {
+            init();
+        }
+
+        // Call the global start function if present.  Otherwise show the stage.
+        if ($GLOBAL.start) {
+            start(stage);
+        } else {
+            stage.show();
+        }
+    },
+
+    // Overridden javafx.application.Application.stop();
+    stop: function() {
+        // Call the global stop function if present.
+        if ($GLOBAL.stop) {
+            stop();
+        }
+    }
+
+    // No arguments passed to application (handled thru $ARG.)
+})).class, new (Java.type("java.lang.String[]"))(0));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/controls.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+AreaChart                                  = Java.type("javafx.scene.chart.AreaChart");
+AreaChartBuilder                           = Java.type("javafx.scene.chart.AreaChartBuilder");
+Axis                                       = Java.type("javafx.scene.chart.Axis");
+Axis$TickMark                              = Java.type("javafx.scene.chart.Axis$TickMark");
+AxisBuilder                                = Java.type("javafx.scene.chart.AxisBuilder");
+BarChart                                   = Java.type("javafx.scene.chart.BarChart");
+BarChartBuilder                            = Java.type("javafx.scene.chart.BarChartBuilder");
+BubbleChart                                = Java.type("javafx.scene.chart.BubbleChart");
+BubbleChartBuilder                         = Java.type("javafx.scene.chart.BubbleChartBuilder");
+CategoryAxis                               = Java.type("javafx.scene.chart.CategoryAxis");
+CategoryAxisBuilder                        = Java.type("javafx.scene.chart.CategoryAxisBuilder");
+Chart                                      = Java.type("javafx.scene.chart.Chart");
+ChartBuilder                               = Java.type("javafx.scene.chart.ChartBuilder");
+LineChart                                  = Java.type("javafx.scene.chart.LineChart");
+LineChartBuilder                           = Java.type("javafx.scene.chart.LineChartBuilder");
+NumberAxis                                 = Java.type("javafx.scene.chart.NumberAxis");
+NumberAxis$DefaultFormatter                = Java.type("javafx.scene.chart.NumberAxis$DefaultFormatter");
+NumberAxisBuilder                          = Java.type("javafx.scene.chart.NumberAxisBuilder");
+PieChart                                   = Java.type("javafx.scene.chart.PieChart");
+PieChart$Data                              = Java.type("javafx.scene.chart.PieChart$Data");
+PieChartBuilder                            = Java.type("javafx.scene.chart.PieChartBuilder");
+ScatterChart                               = Java.type("javafx.scene.chart.ScatterChart");
+ScatterChartBuilder                        = Java.type("javafx.scene.chart.ScatterChartBuilder");
+StackedAreaChart                           = Java.type("javafx.scene.chart.StackedAreaChart");
+StackedAreaChartBuilder                    = Java.type("javafx.scene.chart.StackedAreaChartBuilder");
+StackedBarChart                            = Java.type("javafx.scene.chart.StackedBarChart");
+StackedBarChartBuilder                     = Java.type("javafx.scene.chart.StackedBarChartBuilder");
+ValueAxis                                  = Java.type("javafx.scene.chart.ValueAxis");
+ValueAxisBuilder                           = Java.type("javafx.scene.chart.ValueAxisBuilder");
+XYChart                                    = Java.type("javafx.scene.chart.XYChart");
+XYChart$Data                               = Java.type("javafx.scene.chart.XYChart$Data");
+XYChart$Series                             = Java.type("javafx.scene.chart.XYChart$Series");
+XYChartBuilder                             = Java.type("javafx.scene.chart.XYChartBuilder");
+Accordion                                  = Java.type("javafx.scene.control.Accordion");
+AccordionBuilder                           = Java.type("javafx.scene.control.AccordionBuilder");
+Button                                     = Java.type("javafx.scene.control.Button");
+ButtonBase                                 = Java.type("javafx.scene.control.ButtonBase");
+ButtonBaseBuilder                          = Java.type("javafx.scene.control.ButtonBaseBuilder");
+ButtonBuilder                              = Java.type("javafx.scene.control.ButtonBuilder");
+Cell                                       = Java.type("javafx.scene.control.Cell");
+CheckBoxListCell                           = Java.type("javafx.scene.control.cell.CheckBoxListCell");
+CheckBoxListCellBuilder                    = Java.type("javafx.scene.control.cell.CheckBoxListCellBuilder");
+CheckBoxTableCell                          = Java.type("javafx.scene.control.cell.CheckBoxTableCell");
+CheckBoxTableCellBuilder                   = Java.type("javafx.scene.control.cell.CheckBoxTableCellBuilder");
+CheckBoxTreeCell                           = Java.type("javafx.scene.control.cell.CheckBoxTreeCell");
+CheckBoxTreeCellBuilder                    = Java.type("javafx.scene.control.cell.CheckBoxTreeCellBuilder");
+CheckBoxTreeTableCell                      = Java.type("javafx.scene.control.cell.CheckBoxTreeTableCell");
+CheckBoxTreeTableCellBuilder               = Java.type("javafx.scene.control.cell.CheckBoxTreeTableCellBuilder");
+ChoiceBoxListCell                          = Java.type("javafx.scene.control.cell.ChoiceBoxListCell");
+ChoiceBoxListCellBuilder                   = Java.type("javafx.scene.control.cell.ChoiceBoxListCellBuilder");
+ChoiceBoxTableCell                         = Java.type("javafx.scene.control.cell.ChoiceBoxTableCell");
+ChoiceBoxTableCellBuilder                  = Java.type("javafx.scene.control.cell.ChoiceBoxTableCellBuilder");
+ChoiceBoxTreeCell                          = Java.type("javafx.scene.control.cell.ChoiceBoxTreeCell");
+ChoiceBoxTreeCellBuilder                   = Java.type("javafx.scene.control.cell.ChoiceBoxTreeCellBuilder");
+ChoiceBoxTreeTableCell                     = Java.type("javafx.scene.control.cell.ChoiceBoxTreeTableCell");
+ChoiceBoxTreeTableCellBuilder              = Java.type("javafx.scene.control.cell.ChoiceBoxTreeTableCellBuilder");
+ComboBoxListCell                           = Java.type("javafx.scene.control.cell.ComboBoxListCell");
+ComboBoxListCellBuilder                    = Java.type("javafx.scene.control.cell.ComboBoxListCellBuilder");
+ComboBoxTableCell                          = Java.type("javafx.scene.control.cell.ComboBoxTableCell");
+ComboBoxTableCellBuilder                   = Java.type("javafx.scene.control.cell.ComboBoxTableCellBuilder");
+ComboBoxTreeCell                           = Java.type("javafx.scene.control.cell.ComboBoxTreeCell");
+ComboBoxTreeCellBuilder                    = Java.type("javafx.scene.control.cell.ComboBoxTreeCellBuilder");
+ComboBoxTreeTableCell                      = Java.type("javafx.scene.control.cell.ComboBoxTreeTableCell");
+ComboBoxTreeTableCellBuilder               = Java.type("javafx.scene.control.cell.ComboBoxTreeTableCellBuilder");
+MapValueFactory                            = Java.type("javafx.scene.control.cell.MapValueFactory");
+ProgressBarTableCell                       = Java.type("javafx.scene.control.cell.ProgressBarTableCell");
+ProgressBarTreeTableCell                   = Java.type("javafx.scene.control.cell.ProgressBarTreeTableCell");
+PropertyValueFactory                       = Java.type("javafx.scene.control.cell.PropertyValueFactory");
+PropertyValueFactoryBuilder                = Java.type("javafx.scene.control.cell.PropertyValueFactoryBuilder");
+TextFieldListCell                          = Java.type("javafx.scene.control.cell.TextFieldListCell");
+TextFieldListCellBuilder                   = Java.type("javafx.scene.control.cell.TextFieldListCellBuilder");
+TextFieldTableCell                         = Java.type("javafx.scene.control.cell.TextFieldTableCell");
+TextFieldTableCellBuilder                  = Java.type("javafx.scene.control.cell.TextFieldTableCellBuilder");
+TextFieldTreeCell                          = Java.type("javafx.scene.control.cell.TextFieldTreeCell");
+TextFieldTreeCellBuilder                   = Java.type("javafx.scene.control.cell.TextFieldTreeCellBuilder");
+TextFieldTreeTableCell                     = Java.type("javafx.scene.control.cell.TextFieldTreeTableCell");
+TextFieldTreeTableCellBuilder              = Java.type("javafx.scene.control.cell.TextFieldTreeTableCellBuilder");
+TreeItemPropertyValueFactory               = Java.type("javafx.scene.control.cell.TreeItemPropertyValueFactory");
+TreeItemPropertyValueFactoryBuilder        = Java.type("javafx.scene.control.cell.TreeItemPropertyValueFactoryBuilder");
+CellBuilder                                = Java.type("javafx.scene.control.CellBuilder");
+CheckBox                                   = Java.type("javafx.scene.control.CheckBox");
+CheckBoxBuilder                            = Java.type("javafx.scene.control.CheckBoxBuilder");
+CheckBoxTreeItem                           = Java.type("javafx.scene.control.CheckBoxTreeItem");
+CheckBoxTreeItem$TreeModificationEvent     = Java.type("javafx.scene.control.CheckBoxTreeItem$TreeModificationEvent");
+CheckBoxTreeItemBuilder                    = Java.type("javafx.scene.control.CheckBoxTreeItemBuilder");
+CheckMenuItem                              = Java.type("javafx.scene.control.CheckMenuItem");
+CheckMenuItemBuilder                       = Java.type("javafx.scene.control.CheckMenuItemBuilder");
+ChoiceBox                                  = Java.type("javafx.scene.control.ChoiceBox");
+ChoiceBoxBuilder                           = Java.type("javafx.scene.control.ChoiceBoxBuilder");
+ColorPicker                                = Java.type("javafx.scene.control.ColorPicker");
+ColorPickerBuilder                         = Java.type("javafx.scene.control.ColorPickerBuilder");
+ComboBox                                   = Java.type("javafx.scene.control.ComboBox");
+ComboBoxBase                               = Java.type("javafx.scene.control.ComboBoxBase");
+ComboBoxBaseBuilder                        = Java.type("javafx.scene.control.ComboBoxBaseBuilder");
+ComboBoxBuilder                            = Java.type("javafx.scene.control.ComboBoxBuilder");
+ContentDisplay                             = Java.type("javafx.scene.control.ContentDisplay");
+ContextMenu                                = Java.type("javafx.scene.control.ContextMenu");
+ContextMenuBuilder                         = Java.type("javafx.scene.control.ContextMenuBuilder");
+Control                                    = Java.type("javafx.scene.control.Control");
+ControlBuilder                             = Java.type("javafx.scene.control.ControlBuilder");
+CustomMenuItem                             = Java.type("javafx.scene.control.CustomMenuItem");
+CustomMenuItemBuilder                      = Java.type("javafx.scene.control.CustomMenuItemBuilder");
+FocusModel                                 = Java.type("javafx.scene.control.FocusModel");
+Hyperlink                                  = Java.type("javafx.scene.control.Hyperlink");
+HyperlinkBuilder                           = Java.type("javafx.scene.control.HyperlinkBuilder");
+IndexedCell                                = Java.type("javafx.scene.control.IndexedCell");
+IndexedCellBuilder                         = Java.type("javafx.scene.control.IndexedCellBuilder");
+IndexRange                                 = Java.type("javafx.scene.control.IndexRange");
+IndexRangeBuilder                          = Java.type("javafx.scene.control.IndexRangeBuilder");
+Label                                      = Java.type("javafx.scene.control.Label");
+LabelBuilder                               = Java.type("javafx.scene.control.LabelBuilder");
+Labeled                                    = Java.type("javafx.scene.control.Labeled");
+LabeledBuilder                             = Java.type("javafx.scene.control.LabeledBuilder");
+ListCell                                   = Java.type("javafx.scene.control.ListCell");
+ListCellBuilder                            = Java.type("javafx.scene.control.ListCellBuilder");
+ListView                                   = Java.type("javafx.scene.control.ListView");
+ListView$EditEvent                         = Java.type("javafx.scene.control.ListView$EditEvent");
+ListViewBuilder                            = Java.type("javafx.scene.control.ListViewBuilder");
+Menu                                       = Java.type("javafx.scene.control.Menu");
+MenuBar                                    = Java.type("javafx.scene.control.MenuBar");
+MenuBarBuilder                             = Java.type("javafx.scene.control.MenuBarBuilder");
+MenuBuilder                                = Java.type("javafx.scene.control.MenuBuilder");
+MenuButton                                 = Java.type("javafx.scene.control.MenuButton");
+MenuButtonBuilder                          = Java.type("javafx.scene.control.MenuButtonBuilder");
+MenuItem                                   = Java.type("javafx.scene.control.MenuItem");
+MenuItemBuilder                            = Java.type("javafx.scene.control.MenuItemBuilder");
+MultipleSelectionModel                     = Java.type("javafx.scene.control.MultipleSelectionModel");
+MultipleSelectionModelBuilder              = Java.type("javafx.scene.control.MultipleSelectionModelBuilder");
+OverrunStyle                               = Java.type("javafx.scene.control.OverrunStyle");
+Pagination                                 = Java.type("javafx.scene.control.Pagination");
+PaginationBuilder                          = Java.type("javafx.scene.control.PaginationBuilder");
+PasswordField                              = Java.type("javafx.scene.control.PasswordField");
+PasswordFieldBuilder                       = Java.type("javafx.scene.control.PasswordFieldBuilder");
+PopupControl                               = Java.type("javafx.scene.control.PopupControl");
+PopupControlBuilder                        = Java.type("javafx.scene.control.PopupControlBuilder");
+ProgressBar                                = Java.type("javafx.scene.control.ProgressBar");
+ProgressBarBuilder                         = Java.type("javafx.scene.control.ProgressBarBuilder");
+ProgressIndicator                          = Java.type("javafx.scene.control.ProgressIndicator");
+ProgressIndicatorBuilder                   = Java.type("javafx.scene.control.ProgressIndicatorBuilder");
+RadioButton                                = Java.type("javafx.scene.control.RadioButton");
+RadioButtonBuilder                         = Java.type("javafx.scene.control.RadioButtonBuilder");
+RadioMenuItem                              = Java.type("javafx.scene.control.RadioMenuItem");
+RadioMenuItemBuilder                       = Java.type("javafx.scene.control.RadioMenuItemBuilder");
+ResizeFeaturesBase                         = Java.type("javafx.scene.control.ResizeFeaturesBase");
+ResizeFeaturesBaseBuilder                  = Java.type("javafx.scene.control.ResizeFeaturesBaseBuilder");
+ScrollBar                                  = Java.type("javafx.scene.control.ScrollBar");
+ScrollBarBuilder                           = Java.type("javafx.scene.control.ScrollBarBuilder");
+ScrollPane                                 = Java.type("javafx.scene.control.ScrollPane");
+ScrollPane$ScrollBarPolicy                 = Java.type("javafx.scene.control.ScrollPane$ScrollBarPolicy");
+ScrollPaneBuilder                          = Java.type("javafx.scene.control.ScrollPaneBuilder");
+ScrollToEvent                              = Java.type("javafx.scene.control.ScrollToEvent");
+SelectionMode                              = Java.type("javafx.scene.control.SelectionMode");
+SelectionModel                             = Java.type("javafx.scene.control.SelectionModel");
+Separator                                  = Java.type("javafx.scene.control.Separator");
+SeparatorBuilder                           = Java.type("javafx.scene.control.SeparatorBuilder");
+SeparatorMenuItem                          = Java.type("javafx.scene.control.SeparatorMenuItem");
+SeparatorMenuItemBuilder                   = Java.type("javafx.scene.control.SeparatorMenuItemBuilder");
+SingleSelectionModel                       = Java.type("javafx.scene.control.SingleSelectionModel");
+Skin                                       = Java.type("javafx.scene.control.Skin");
+SkinBase                                   = Java.type("javafx.scene.control.SkinBase");
+SkinBaseBuilder                            = Java.type("javafx.scene.control.SkinBaseBuilder");
+Skinnable                                  = Java.type("javafx.scene.control.Skinnable");
+Slider                                     = Java.type("javafx.scene.control.Slider");
+SliderBuilder                              = Java.type("javafx.scene.control.SliderBuilder");
+SortEvent                                  = Java.type("javafx.scene.control.SortEvent");
+SplitMenuButton                            = Java.type("javafx.scene.control.SplitMenuButton");
+SplitMenuButtonBuilder                     = Java.type("javafx.scene.control.SplitMenuButtonBuilder");
+SplitPane                                  = Java.type("javafx.scene.control.SplitPane");
+SplitPane$Divider                          = Java.type("javafx.scene.control.SplitPane$Divider");
+SplitPaneBuilder                           = Java.type("javafx.scene.control.SplitPaneBuilder");
+Tab                                        = Java.type("javafx.scene.control.Tab");
+TabBuilder                                 = Java.type("javafx.scene.control.TabBuilder");
+TableCell                                  = Java.type("javafx.scene.control.TableCell");
+TableCellBuilder                           = Java.type("javafx.scene.control.TableCellBuilder");
+TableColumn                                = Java.type("javafx.scene.control.TableColumn");
+TableColumn$CellDataFeatures               = Java.type("javafx.scene.control.TableColumn$CellDataFeatures");
+TableColumn$CellEditEvent                  = Java.type("javafx.scene.control.TableColumn$CellEditEvent");
+TableColumn$SortType                       = Java.type("javafx.scene.control.TableColumn$SortType");
+TableColumnBase                            = Java.type("javafx.scene.control.TableColumnBase");
+TableColumnBaseBuilder                     = Java.type("javafx.scene.control.TableColumnBaseBuilder");
+TableColumnBuilder                         = Java.type("javafx.scene.control.TableColumnBuilder");
+TableFocusModel                            = Java.type("javafx.scene.control.TableFocusModel");
+TablePosition                              = Java.type("javafx.scene.control.TablePosition");
+TablePositionBase                          = Java.type("javafx.scene.control.TablePositionBase");
+TableRow                                   = Java.type("javafx.scene.control.TableRow");
+TableRowBuilder                            = Java.type("javafx.scene.control.TableRowBuilder");
+TableSelectionModel                        = Java.type("javafx.scene.control.TableSelectionModel");
+TableSelectionModelBuilder                 = Java.type("javafx.scene.control.TableSelectionModelBuilder");
+TableView                                  = Java.type("javafx.scene.control.TableView");
+TableView$ResizeFeatures                   = Java.type("javafx.scene.control.TableView$ResizeFeatures");
+TableView$TableViewFocusModel              = Java.type("javafx.scene.control.TableView$TableViewFocusModel");
+TableView$TableViewSelectionModel          = Java.type("javafx.scene.control.TableView$TableViewSelectionModel");
+TableViewBuilder                           = Java.type("javafx.scene.control.TableViewBuilder");
+TabPane                                    = Java.type("javafx.scene.control.TabPane");
+TabPane$TabClosingPolicy                   = Java.type("javafx.scene.control.TabPane$TabClosingPolicy");
+TabPaneBuilder                             = Java.type("javafx.scene.control.TabPaneBuilder");
+TextArea                                   = Java.type("javafx.scene.control.TextArea");
+TextAreaBuilder                            = Java.type("javafx.scene.control.TextAreaBuilder");
+TextField                                  = Java.type("javafx.scene.control.TextField");
+TextFieldBuilder                           = Java.type("javafx.scene.control.TextFieldBuilder");
+TextInputControl                           = Java.type("javafx.scene.control.TextInputControl");
+TextInputControl$Content                   = Java.type("javafx.scene.control.TextInputControl$Content");
+TextInputControlBuilder                    = Java.type("javafx.scene.control.TextInputControlBuilder");
+TitledPane                                 = Java.type("javafx.scene.control.TitledPane");
+TitledPaneBuilder                          = Java.type("javafx.scene.control.TitledPaneBuilder");
+Toggle                                     = Java.type("javafx.scene.control.Toggle");
+ToggleButton                               = Java.type("javafx.scene.control.ToggleButton");
+ToggleButtonBuilder                        = Java.type("javafx.scene.control.ToggleButtonBuilder");
+ToggleGroup                                = Java.type("javafx.scene.control.ToggleGroup");
+ToggleGroupBuilder                         = Java.type("javafx.scene.control.ToggleGroupBuilder");
+ToolBar                                    = Java.type("javafx.scene.control.ToolBar");
+ToolBarBuilder                             = Java.type("javafx.scene.control.ToolBarBuilder");
+Tooltip                                    = Java.type("javafx.scene.control.Tooltip");
+TooltipBuilder                             = Java.type("javafx.scene.control.TooltipBuilder");
+TreeCell                                   = Java.type("javafx.scene.control.TreeCell");
+TreeCellBuilder                            = Java.type("javafx.scene.control.TreeCellBuilder");
+TreeItem                                   = Java.type("javafx.scene.control.TreeItem");
+TreeItem$TreeModificationEvent             = Java.type("javafx.scene.control.TreeItem$TreeModificationEvent");
+TreeItemBuilder                            = Java.type("javafx.scene.control.TreeItemBuilder");
+TreeSortMode                               = Java.type("javafx.scene.control.TreeSortMode");
+TreeTableCell                              = Java.type("javafx.scene.control.TreeTableCell");
+TreeTableCellBuilder                       = Java.type("javafx.scene.control.TreeTableCellBuilder");
+TreeTableColumn                            = Java.type("javafx.scene.control.TreeTableColumn");
+TreeTableColumn$CellDataFeatures           = Java.type("javafx.scene.control.TreeTableColumn$CellDataFeatures");
+TreeTableColumn$CellEditEvent              = Java.type("javafx.scene.control.TreeTableColumn$CellEditEvent");
+TreeTableColumn$SortType                   = Java.type("javafx.scene.control.TreeTableColumn$SortType");
+TreeTableColumnBuilder                     = Java.type("javafx.scene.control.TreeTableColumnBuilder");
+TreeTablePosition                          = Java.type("javafx.scene.control.TreeTablePosition");
+TreeTableRow                               = Java.type("javafx.scene.control.TreeTableRow");
+TreeTableRowBuilder                        = Java.type("javafx.scene.control.TreeTableRowBuilder");
+TreeTableView                              = Java.type("javafx.scene.control.TreeTableView");
+TreeTableView$EditEvent                    = Java.type("javafx.scene.control.TreeTableView$EditEvent");
+TreeTableView$ResizeFeatures               = Java.type("javafx.scene.control.TreeTableView$ResizeFeatures");
+TreeTableView$TreeTableViewFocusModel      = Java.type("javafx.scene.control.TreeTableView$TreeTableViewFocusModel");
+TreeTableView$TreeTableViewSelectionModel  = Java.type("javafx.scene.control.TreeTableView$TreeTableViewSelectionModel");
+TreeTableViewBuilder                       = Java.type("javafx.scene.control.TreeTableViewBuilder");
+TreeView                                   = Java.type("javafx.scene.control.TreeView");
+TreeView$EditEvent                         = Java.type("javafx.scene.control.TreeView$EditEvent");
+TreeViewBuilder                            = Java.type("javafx.scene.control.TreeViewBuilder");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/fxml.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+FXML                 = Java.type("javafx.fxml.FXML");
+FXMLLoader           = Java.type("javafx.fxml.FXMLLoader");
+Initializable        = Java.type("javafx.fxml.Initializable");
+JavaFXBuilderFactory = Java.type("javafx.fxml.JavaFXBuilderFactory");
+LoadException        = Java.type("javafx.fxml.LoadException");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/graphics.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,431 @@
+/*
+ * 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.
+ */
+
+Animation                              = Java.type("javafx.animation.Animation");
+Animation$Status                       = Java.type("javafx.animation.Animation$Status");
+AnimationBuilder                       = Java.type("javafx.animation.AnimationBuilder");
+AnimationTimer                         = Java.type("javafx.animation.AnimationTimer");
+FadeTransition                         = Java.type("javafx.animation.FadeTransition");
+FadeTransitionBuilder                  = Java.type("javafx.animation.FadeTransitionBuilder");
+FillTransition                         = Java.type("javafx.animation.FillTransition");
+FillTransitionBuilder                  = Java.type("javafx.animation.FillTransitionBuilder");
+Interpolatable                         = Java.type("javafx.animation.Interpolatable");
+Interpolator                           = Java.type("javafx.animation.Interpolator");
+KeyFrame                               = Java.type("javafx.animation.KeyFrame");
+KeyValue                               = Java.type("javafx.animation.KeyValue");
+ParallelTransition                     = Java.type("javafx.animation.ParallelTransition");
+ParallelTransitionBuilder              = Java.type("javafx.animation.ParallelTransitionBuilder");
+PathTransition                         = Java.type("javafx.animation.PathTransition");
+PathTransition$OrientationType         = Java.type("javafx.animation.PathTransition$OrientationType");
+PathTransitionBuilder                  = Java.type("javafx.animation.PathTransitionBuilder");
+PauseTransition                        = Java.type("javafx.animation.PauseTransition");
+PauseTransitionBuilder                 = Java.type("javafx.animation.PauseTransitionBuilder");
+RotateTransition                       = Java.type("javafx.animation.RotateTransition");
+RotateTransitionBuilder                = Java.type("javafx.animation.RotateTransitionBuilder");
+ScaleTransition                        = Java.type("javafx.animation.ScaleTransition");
+ScaleTransitionBuilder                 = Java.type("javafx.animation.ScaleTransitionBuilder");
+SequentialTransition                   = Java.type("javafx.animation.SequentialTransition");
+SequentialTransitionBuilder            = Java.type("javafx.animation.SequentialTransitionBuilder");
+StrokeTransition                       = Java.type("javafx.animation.StrokeTransition");
+StrokeTransitionBuilder                = Java.type("javafx.animation.StrokeTransitionBuilder");
+Timeline                               = Java.type("javafx.animation.Timeline");
+TimelineBuilder                        = Java.type("javafx.animation.TimelineBuilder");
+Transition                             = Java.type("javafx.animation.Transition");
+TransitionBuilder                      = Java.type("javafx.animation.TransitionBuilder");
+TranslateTransition                    = Java.type("javafx.animation.TranslateTransition");
+TranslateTransitionBuilder             = Java.type("javafx.animation.TranslateTransitionBuilder");
+Application                            = Java.type("javafx.application.Application");
+Application$Parameters                 = Java.type("javafx.application.Application$Parameters");
+ConditionalFeature                     = Java.type("javafx.application.ConditionalFeature");
+HostServices                           = Java.type("javafx.application.HostServices");
+Platform                               = Java.type("javafx.application.Platform");
+Preloader                              = Java.type("javafx.application.Preloader");
+Preloader$ErrorNotification            = Java.type("javafx.application.Preloader$ErrorNotification");
+Preloader$PreloaderNotification        = Java.type("javafx.application.Preloader$PreloaderNotification");
+Preloader$ProgressNotification         = Java.type("javafx.application.Preloader$ProgressNotification");
+Preloader$StateChangeNotification      = Java.type("javafx.application.Preloader$StateChangeNotification");
+Preloader$StateChangeNotification$Type = Java.type("javafx.application.Preloader$StateChangeNotification$Type");
+ScheduledService                       = Java.type("javafx.concurrent.ScheduledService");
+Service                                = Java.type("javafx.concurrent.Service");
+Task                                   = Java.type("javafx.concurrent.Task");
+Worker                                 = Java.type("javafx.concurrent.Worker");
+Worker$State                           = Java.type("javafx.concurrent.Worker$State");
+WorkerStateEvent                       = Java.type("javafx.concurrent.WorkerStateEvent");
+CssMetaData                            = Java.type("javafx.css.CssMetaData");
+FontCssMetaData                        = Java.type("javafx.css.FontCssMetaData");
+ParsedValue                            = Java.type("javafx.css.ParsedValue");
+PseudoClass                            = Java.type("javafx.css.PseudoClass");
+SimpleStyleableBooleanProperty         = Java.type("javafx.css.SimpleStyleableBooleanProperty");
+SimpleStyleableDoubleProperty          = Java.type("javafx.css.SimpleStyleableDoubleProperty");
+SimpleStyleableFloatProperty           = Java.type("javafx.css.SimpleStyleableFloatProperty");
+SimpleStyleableIntegerProperty         = Java.type("javafx.css.SimpleStyleableIntegerProperty");
+SimpleStyleableLongProperty            = Java.type("javafx.css.SimpleStyleableLongProperty");
+SimpleStyleableObjectProperty          = Java.type("javafx.css.SimpleStyleableObjectProperty");
+SimpleStyleableStringProperty          = Java.type("javafx.css.SimpleStyleableStringProperty");
+Styleable                              = Java.type("javafx.css.Styleable");
+StyleableBooleanProperty               = Java.type("javafx.css.StyleableBooleanProperty");
+StyleableDoubleProperty                = Java.type("javafx.css.StyleableDoubleProperty");
+StyleableFloatProperty                 = Java.type("javafx.css.StyleableFloatProperty");
+StyleableIntegerProperty               = Java.type("javafx.css.StyleableIntegerProperty");
+StyleableLongProperty                  = Java.type("javafx.css.StyleableLongProperty");
+StyleableObjectProperty                = Java.type("javafx.css.StyleableObjectProperty");
+StyleableProperty                      = Java.type("javafx.css.StyleableProperty");
+StyleableStringProperty                = Java.type("javafx.css.StyleableStringProperty");
+StyleConverter                         = Java.type("javafx.css.StyleConverter");
+StyleOrigin                            = Java.type("javafx.css.StyleOrigin");
+BoundingBox                            = Java.type("javafx.geometry.BoundingBox");
+BoundingBoxBuilder                     = Java.type("javafx.geometry.BoundingBoxBuilder");
+Bounds                                 = Java.type("javafx.geometry.Bounds");
+Dimension2D                            = Java.type("javafx.geometry.Dimension2D");
+Dimension2DBuilder                     = Java.type("javafx.geometry.Dimension2DBuilder");
+HorizontalDirection                    = Java.type("javafx.geometry.HorizontalDirection");
+HPos                                   = Java.type("javafx.geometry.HPos");
+Insets                                 = Java.type("javafx.geometry.Insets");
+InsetsBuilder                          = Java.type("javafx.geometry.InsetsBuilder");
+NodeOrientation                        = Java.type("javafx.geometry.NodeOrientation");
+Orientation                            = Java.type("javafx.geometry.Orientation");
+Point2D                                = Java.type("javafx.geometry.Point2D");
+Point2DBuilder                         = Java.type("javafx.geometry.Point2DBuilder");
+Point3D                                = Java.type("javafx.geometry.Point3D");
+Point3DBuilder                         = Java.type("javafx.geometry.Point3DBuilder");
+Pos                                    = Java.type("javafx.geometry.Pos");
+Rectangle2D                            = Java.type("javafx.geometry.Rectangle2D");
+Rectangle2DBuilder                     = Java.type("javafx.geometry.Rectangle2DBuilder");
+Side                                   = Java.type("javafx.geometry.Side");
+VerticalDirection                      = Java.type("javafx.geometry.VerticalDirection");
+VPos                                   = Java.type("javafx.geometry.VPos");
+Collation                              = Java.type("javafx.print.Collation");
+JobSettings                            = Java.type("javafx.print.JobSettings");
+PageLayout                             = Java.type("javafx.print.PageLayout");
+PageOrientation                        = Java.type("javafx.print.PageOrientation");
+PageRange                              = Java.type("javafx.print.PageRange");
+Paper                                  = Java.type("javafx.print.Paper");
+Paper$Units                            = Java.type("javafx.print.Paper$Units");
+PaperSource                            = Java.type("javafx.print.PaperSource");
+PrintColor                             = Java.type("javafx.print.PrintColor");
+Printer                                = Java.type("javafx.print.Printer");
+Printer$MarginType                     = Java.type("javafx.print.Printer$MarginType");
+PrinterAttributes                      = Java.type("javafx.print.PrinterAttributes");
+PrinterJob                             = Java.type("javafx.print.PrinterJob");
+PrinterJob$JobStatus                   = Java.type("javafx.print.PrinterJob$JobStatus");
+PrintQuality                           = Java.type("javafx.print.PrintQuality");
+PrintResolution                        = Java.type("javafx.print.PrintResolution");
+PrintSides                             = Java.type("javafx.print.PrintSides");
+AmbientLight                           = Java.type("javafx.scene.AmbientLight");
+AmbientLightBuilder                    = Java.type("javafx.scene.AmbientLightBuilder");
+CacheHint                              = Java.type("javafx.scene.CacheHint");
+Camera                                 = Java.type("javafx.scene.Camera");
+CameraBuilder                          = Java.type("javafx.scene.CameraBuilder");
+Canvas                                 = Java.type("javafx.scene.canvas.Canvas");
+CanvasBuilder                          = Java.type("javafx.scene.canvas.CanvasBuilder");
+GraphicsContext                        = Java.type("javafx.scene.canvas.GraphicsContext");
+Cursor                                 = Java.type("javafx.scene.Cursor");
+DepthTest                              = Java.type("javafx.scene.DepthTest");
+Blend                                  = Java.type("javafx.scene.effect.Blend");
+BlendBuilder                           = Java.type("javafx.scene.effect.BlendBuilder");
+BlendMode                              = Java.type("javafx.scene.effect.BlendMode");
+Bloom                                  = Java.type("javafx.scene.effect.Bloom");
+BloomBuilder                           = Java.type("javafx.scene.effect.BloomBuilder");
+BlurType                               = Java.type("javafx.scene.effect.BlurType");
+BoxBlur                                = Java.type("javafx.scene.effect.BoxBlur");
+BoxBlurBuilder                         = Java.type("javafx.scene.effect.BoxBlurBuilder");
+ColorAdjust                            = Java.type("javafx.scene.effect.ColorAdjust");
+ColorAdjustBuilder                     = Java.type("javafx.scene.effect.ColorAdjustBuilder");
+ColorInput                             = Java.type("javafx.scene.effect.ColorInput");
+ColorInputBuilder                      = Java.type("javafx.scene.effect.ColorInputBuilder");
+DisplacementMap                        = Java.type("javafx.scene.effect.DisplacementMap");
+DisplacementMapBuilder                 = Java.type("javafx.scene.effect.DisplacementMapBuilder");
+DropShadow                             = Java.type("javafx.scene.effect.DropShadow");
+DropShadowBuilder                      = Java.type("javafx.scene.effect.DropShadowBuilder");
+Effect                                 = Java.type("javafx.scene.effect.Effect");
+FloatMap                               = Java.type("javafx.scene.effect.FloatMap");
+FloatMapBuilder                        = Java.type("javafx.scene.effect.FloatMapBuilder");
+GaussianBlur                           = Java.type("javafx.scene.effect.GaussianBlur");
+GaussianBlurBuilder                    = Java.type("javafx.scene.effect.GaussianBlurBuilder");
+Glow                                   = Java.type("javafx.scene.effect.Glow");
+GlowBuilder                            = Java.type("javafx.scene.effect.GlowBuilder");
+ImageInput                             = Java.type("javafx.scene.effect.ImageInput");
+ImageInputBuilder                      = Java.type("javafx.scene.effect.ImageInputBuilder");
+InnerShadow                            = Java.type("javafx.scene.effect.InnerShadow");
+InnerShadowBuilder                     = Java.type("javafx.scene.effect.InnerShadowBuilder");
+Light                                  = Java.type("javafx.scene.effect.Light");
+Light$Distant                          = Java.type("javafx.scene.effect.Light$Distant");
+Light$Point                            = Java.type("javafx.scene.effect.Light$Point");
+Light$Spot                             = Java.type("javafx.scene.effect.Light$Spot");
+LightBuilder                           = Java.type("javafx.scene.effect.LightBuilder");
+Lighting                               = Java.type("javafx.scene.effect.Lighting");
+LightingBuilder                        = Java.type("javafx.scene.effect.LightingBuilder");
+MotionBlur                             = Java.type("javafx.scene.effect.MotionBlur");
+MotionBlurBuilder                      = Java.type("javafx.scene.effect.MotionBlurBuilder");
+PerspectiveTransform                   = Java.type("javafx.scene.effect.PerspectiveTransform");
+PerspectiveTransformBuilder            = Java.type("javafx.scene.effect.PerspectiveTransformBuilder");
+Reflection                             = Java.type("javafx.scene.effect.Reflection");
+ReflectionBuilder                      = Java.type("javafx.scene.effect.ReflectionBuilder");
+SepiaTone                              = Java.type("javafx.scene.effect.SepiaTone");
+SepiaToneBuilder                       = Java.type("javafx.scene.effect.SepiaToneBuilder");
+Shadow                                 = Java.type("javafx.scene.effect.Shadow");
+ShadowBuilder                          = Java.type("javafx.scene.effect.ShadowBuilder");
+//Group                                  = Java.type("javafx.scene.Group");
+GroupBuilder                           = Java.type("javafx.scene.GroupBuilder");
+Image                                  = Java.type("javafx.scene.image.Image");
+ImageView                              = Java.type("javafx.scene.image.ImageView");
+ImageViewBuilder                       = Java.type("javafx.scene.image.ImageViewBuilder");
+PixelFormat                            = Java.type("javafx.scene.image.PixelFormat");
+PixelFormat$Type                       = Java.type("javafx.scene.image.PixelFormat$Type");
+PixelReader                            = Java.type("javafx.scene.image.PixelReader");
+PixelWriter                            = Java.type("javafx.scene.image.PixelWriter");
+WritableImage                          = Java.type("javafx.scene.image.WritableImage");
+WritablePixelFormat                    = Java.type("javafx.scene.image.WritablePixelFormat");
+ImageCursor                            = Java.type("javafx.scene.ImageCursor");
+ImageCursorBuilder                     = Java.type("javafx.scene.ImageCursorBuilder");
+Clipboard                              = Java.type("javafx.scene.input.Clipboard");
+ClipboardContent                       = Java.type("javafx.scene.input.ClipboardContent");
+ClipboardContentBuilder                = Java.type("javafx.scene.input.ClipboardContentBuilder");
+ContextMenuEvent                       = Java.type("javafx.scene.input.ContextMenuEvent");
+DataFormat                             = Java.type("javafx.scene.input.DataFormat");
+Dragboard                              = Java.type("javafx.scene.input.Dragboard");
+DragEvent                              = Java.type("javafx.scene.input.DragEvent");
+GestureEvent                           = Java.type("javafx.scene.input.GestureEvent");
+InputEvent                             = Java.type("javafx.scene.input.InputEvent");
+InputEventBuilder                      = Java.type("javafx.scene.input.InputEventBuilder");
+InputMethodEvent                       = Java.type("javafx.scene.input.InputMethodEvent");
+InputMethodHighlight                   = Java.type("javafx.scene.input.InputMethodHighlight");
+InputMethodRequests                    = Java.type("javafx.scene.input.InputMethodRequests");
+InputMethodTextRun                     = Java.type("javafx.scene.input.InputMethodTextRun");
+InputMethodTextRunBuilder              = Java.type("javafx.scene.input.InputMethodTextRunBuilder");
+KeyCharacterCombination                = Java.type("javafx.scene.input.KeyCharacterCombination");
+KeyCharacterCombinationBuilder         = Java.type("javafx.scene.input.KeyCharacterCombinationBuilder");
+KeyCode                                = Java.type("javafx.scene.input.KeyCode");
+KeyCodeCombination                     = Java.type("javafx.scene.input.KeyCodeCombination");
+KeyCodeCombinationBuilder              = Java.type("javafx.scene.input.KeyCodeCombinationBuilder");
+KeyCombination                         = Java.type("javafx.scene.input.KeyCombination");
+KeyCombination$Modifier                = Java.type("javafx.scene.input.KeyCombination$Modifier");
+KeyCombination$ModifierValue           = Java.type("javafx.scene.input.KeyCombination$ModifierValue");
+KeyEvent                               = Java.type("javafx.scene.input.KeyEvent");
+Mnemonic                               = Java.type("javafx.scene.input.Mnemonic");
+MnemonicBuilder                        = Java.type("javafx.scene.input.MnemonicBuilder");
+MouseButton                            = Java.type("javafx.scene.input.MouseButton");
+MouseDragEvent                         = Java.type("javafx.scene.input.MouseDragEvent");
+MouseEvent                             = Java.type("javafx.scene.input.MouseEvent");
+PickResult                             = Java.type("javafx.scene.input.PickResult");
+RotateEvent                            = Java.type("javafx.scene.input.RotateEvent");
+ScrollEvent                            = Java.type("javafx.scene.input.ScrollEvent");
+ScrollEvent$HorizontalTextScrollUnits  = Java.type("javafx.scene.input.ScrollEvent$HorizontalTextScrollUnits");
+ScrollEvent$VerticalTextScrollUnits    = Java.type("javafx.scene.input.ScrollEvent$VerticalTextScrollUnits");
+SwipeEvent                             = Java.type("javafx.scene.input.SwipeEvent");
+TouchEvent                             = Java.type("javafx.scene.input.TouchEvent");
+TouchPoint                             = Java.type("javafx.scene.input.TouchPoint");
+TouchPoint$State                       = Java.type("javafx.scene.input.TouchPoint$State");
+TouchPointBuilder                      = Java.type("javafx.scene.input.TouchPointBuilder");
+TransferMode                           = Java.type("javafx.scene.input.TransferMode");
+ZoomEvent                              = Java.type("javafx.scene.input.ZoomEvent");
+AnchorPane                             = Java.type("javafx.scene.layout.AnchorPane");
+AnchorPaneBuilder                      = Java.type("javafx.scene.layout.AnchorPaneBuilder");
+Background                             = Java.type("javafx.scene.layout.Background");
+BackgroundBuilder                      = Java.type("javafx.scene.layout.BackgroundBuilder");
+BackgroundFill                         = Java.type("javafx.scene.layout.BackgroundFill");
+BackgroundFillBuilder                  = Java.type("javafx.scene.layout.BackgroundFillBuilder");
+BackgroundImage                        = Java.type("javafx.scene.layout.BackgroundImage");
+BackgroundImageBuilder                 = Java.type("javafx.scene.layout.BackgroundImageBuilder");
+BackgroundPosition                     = Java.type("javafx.scene.layout.BackgroundPosition");
+BackgroundPositionBuilder              = Java.type("javafx.scene.layout.BackgroundPositionBuilder");
+BackgroundRepeat                       = Java.type("javafx.scene.layout.BackgroundRepeat");
+BackgroundSize                         = Java.type("javafx.scene.layout.BackgroundSize");
+BackgroundSizeBuilder                  = Java.type("javafx.scene.layout.BackgroundSizeBuilder");
+Border                                 = Java.type("javafx.scene.layout.Border");
+BorderBuilder                          = Java.type("javafx.scene.layout.BorderBuilder");
+BorderImage                            = Java.type("javafx.scene.layout.BorderImage");
+BorderImageBuilder                     = Java.type("javafx.scene.layout.BorderImageBuilder");
+BorderPane                             = Java.type("javafx.scene.layout.BorderPane");
+BorderPaneBuilder                      = Java.type("javafx.scene.layout.BorderPaneBuilder");
+BorderRepeat                           = Java.type("javafx.scene.layout.BorderRepeat");
+BorderStroke                           = Java.type("javafx.scene.layout.BorderStroke");
+BorderStrokeBuilder                    = Java.type("javafx.scene.layout.BorderStrokeBuilder");
+BorderStrokeStyle                      = Java.type("javafx.scene.layout.BorderStrokeStyle");
+BorderStrokeStyleBuilder               = Java.type("javafx.scene.layout.BorderStrokeStyleBuilder");
+BorderWidths                           = Java.type("javafx.scene.layout.BorderWidths");
+BorderWidthsBuilder                    = Java.type("javafx.scene.layout.BorderWidthsBuilder");
+ColumnConstraints                      = Java.type("javafx.scene.layout.ColumnConstraints");
+ColumnConstraintsBuilder               = Java.type("javafx.scene.layout.ColumnConstraintsBuilder");
+ConstraintsBase                        = Java.type("javafx.scene.layout.ConstraintsBase");
+CornerRadii                            = Java.type("javafx.scene.layout.CornerRadii");
+FlowPane                               = Java.type("javafx.scene.layout.FlowPane");
+FlowPaneBuilder                        = Java.type("javafx.scene.layout.FlowPaneBuilder");
+GridPane                               = Java.type("javafx.scene.layout.GridPane");
+GridPaneBuilder                        = Java.type("javafx.scene.layout.GridPaneBuilder");
+HBox                                   = Java.type("javafx.scene.layout.HBox");
+HBoxBuilder                            = Java.type("javafx.scene.layout.HBoxBuilder");
+Pane                                   = Java.type("javafx.scene.layout.Pane");
+PaneBuilder                            = Java.type("javafx.scene.layout.PaneBuilder");
+Priority                               = Java.type("javafx.scene.layout.Priority");
+Region                                 = Java.type("javafx.scene.layout.Region");
+RegionBuilder                          = Java.type("javafx.scene.layout.RegionBuilder");
+RowConstraints                         = Java.type("javafx.scene.layout.RowConstraints");
+RowConstraintsBuilder                  = Java.type("javafx.scene.layout.RowConstraintsBuilder");
+StackPane                              = Java.type("javafx.scene.layout.StackPane");
+StackPaneBuilder                       = Java.type("javafx.scene.layout.StackPaneBuilder");
+TilePane                               = Java.type("javafx.scene.layout.TilePane");
+TilePaneBuilder                        = Java.type("javafx.scene.layout.TilePaneBuilder");
+VBox                                   = Java.type("javafx.scene.layout.VBox");
+VBoxBuilder                            = Java.type("javafx.scene.layout.VBoxBuilder");
+LightBase                              = Java.type("javafx.scene.LightBase");
+LightBaseBuilder                       = Java.type("javafx.scene.LightBaseBuilder");
+Node                                   = Java.type("javafx.scene.Node");
+NodeBuilder                            = Java.type("javafx.scene.NodeBuilder");
+Color                                  = Java.type("javafx.scene.paint.Color");
+ColorBuilder                           = Java.type("javafx.scene.paint.ColorBuilder");
+CycleMethod                            = Java.type("javafx.scene.paint.CycleMethod");
+ImagePattern                           = Java.type("javafx.scene.paint.ImagePattern");
+ImagePatternBuilder                    = Java.type("javafx.scene.paint.ImagePatternBuilder");
+LinearGradient                         = Java.type("javafx.scene.paint.LinearGradient");
+LinearGradientBuilder                  = Java.type("javafx.scene.paint.LinearGradientBuilder");
+Material                               = Java.type("javafx.scene.paint.Material");
+Paint                                  = Java.type("javafx.scene.paint.Paint");
+PhongMaterial                          = Java.type("javafx.scene.paint.PhongMaterial");
+PhongMaterialBuilder                   = Java.type("javafx.scene.paint.PhongMaterialBuilder");
+RadialGradient                         = Java.type("javafx.scene.paint.RadialGradient");
+RadialGradientBuilder                  = Java.type("javafx.scene.paint.RadialGradientBuilder");
+Stop                                   = Java.type("javafx.scene.paint.Stop");
+StopBuilder                            = Java.type("javafx.scene.paint.StopBuilder");
+ParallelCamera                         = Java.type("javafx.scene.ParallelCamera");
+ParallelCameraBuilder                  = Java.type("javafx.scene.ParallelCameraBuilder");
+Parent                                 = Java.type("javafx.scene.Parent");
+ParentBuilder                          = Java.type("javafx.scene.ParentBuilder");
+PerspectiveCamera                      = Java.type("javafx.scene.PerspectiveCamera");
+PerspectiveCameraBuilder               = Java.type("javafx.scene.PerspectiveCameraBuilder");
+PointLight                             = Java.type("javafx.scene.PointLight");
+PointLightBuilder                      = Java.type("javafx.scene.PointLightBuilder");
+//Scene                                  = Java.type("javafx.scene.Scene");
+SceneBuilder                           = Java.type("javafx.scene.SceneBuilder");
+Arc                                    = Java.type("javafx.scene.shape.Arc");
+ArcBuilder                             = Java.type("javafx.scene.shape.ArcBuilder");
+ArcTo                                  = Java.type("javafx.scene.shape.ArcTo");
+ArcToBuilder                           = Java.type("javafx.scene.shape.ArcToBuilder");
+ArcType                                = Java.type("javafx.scene.shape.ArcType");
+Box                                    = Java.type("javafx.scene.shape.Box");
+BoxBuilder                             = Java.type("javafx.scene.shape.BoxBuilder");
+Circle                                 = Java.type("javafx.scene.shape.Circle");
+CircleBuilder                          = Java.type("javafx.scene.shape.CircleBuilder");
+ClosePath                              = Java.type("javafx.scene.shape.ClosePath");
+ClosePathBuilder                       = Java.type("javafx.scene.shape.ClosePathBuilder");
+CubicCurve                             = Java.type("javafx.scene.shape.CubicCurve");
+CubicCurveBuilder                      = Java.type("javafx.scene.shape.CubicCurveBuilder");
+CubicCurveTo                           = Java.type("javafx.scene.shape.CubicCurveTo");
+CubicCurveToBuilder                    = Java.type("javafx.scene.shape.CubicCurveToBuilder");
+CullFace                               = Java.type("javafx.scene.shape.CullFace");
+Cylinder                               = Java.type("javafx.scene.shape.Cylinder");
+CylinderBuilder                        = Java.type("javafx.scene.shape.CylinderBuilder");
+DrawMode                               = Java.type("javafx.scene.shape.DrawMode");
+Ellipse                                = Java.type("javafx.scene.shape.Ellipse");
+EllipseBuilder                         = Java.type("javafx.scene.shape.EllipseBuilder");
+FillRule                               = Java.type("javafx.scene.shape.FillRule");
+HLineTo                                = Java.type("javafx.scene.shape.HLineTo");
+HLineToBuilder                         = Java.type("javafx.scene.shape.HLineToBuilder");
+Line                                   = Java.type("javafx.scene.shape.Line");
+LineBuilder                            = Java.type("javafx.scene.shape.LineBuilder");
+LineTo                                 = Java.type("javafx.scene.shape.LineTo");
+LineToBuilder                          = Java.type("javafx.scene.shape.LineToBuilder");
+Mesh                                   = Java.type("javafx.scene.shape.Mesh");
+MeshView                               = Java.type("javafx.scene.shape.MeshView");
+MeshViewBuilder                        = Java.type("javafx.scene.shape.MeshViewBuilder");
+MoveTo                                 = Java.type("javafx.scene.shape.MoveTo");
+MoveToBuilder                          = Java.type("javafx.scene.shape.MoveToBuilder");
+Path                                   = Java.type("javafx.scene.shape.Path");
+PathBuilder                            = Java.type("javafx.scene.shape.PathBuilder");
+PathElement                            = Java.type("javafx.scene.shape.PathElement");
+PathElementBuilder                     = Java.type("javafx.scene.shape.PathElementBuilder");
+Polygon                                = Java.type("javafx.scene.shape.Polygon");
+PolygonBuilder                         = Java.type("javafx.scene.shape.PolygonBuilder");
+Polyline                               = Java.type("javafx.scene.shape.Polyline");
+PolylineBuilder                        = Java.type("javafx.scene.shape.PolylineBuilder");
+QuadCurve                              = Java.type("javafx.scene.shape.QuadCurve");
+QuadCurveBuilder                       = Java.type("javafx.scene.shape.QuadCurveBuilder");
+QuadCurveTo                            = Java.type("javafx.scene.shape.QuadCurveTo");
+QuadCurveToBuilder                     = Java.type("javafx.scene.shape.QuadCurveToBuilder");
+Rectangle                              = Java.type("javafx.scene.shape.Rectangle");
+RectangleBuilder                       = Java.type("javafx.scene.shape.RectangleBuilder");
+Shape                                  = Java.type("javafx.scene.shape.Shape");
+Shape3D                                = Java.type("javafx.scene.shape.Shape3D");
+Shape3DBuilder                         = Java.type("javafx.scene.shape.Shape3DBuilder");
+ShapeBuilder                           = Java.type("javafx.scene.shape.ShapeBuilder");
+Sphere                                 = Java.type("javafx.scene.shape.Sphere");
+SphereBuilder                          = Java.type("javafx.scene.shape.SphereBuilder");
+StrokeLineCap                          = Java.type("javafx.scene.shape.StrokeLineCap");
+StrokeLineJoin                         = Java.type("javafx.scene.shape.StrokeLineJoin");
+StrokeType                             = Java.type("javafx.scene.shape.StrokeType");
+SVGPath                                = Java.type("javafx.scene.shape.SVGPath");
+SVGPathBuilder                         = Java.type("javafx.scene.shape.SVGPathBuilder");
+TriangleMesh                           = Java.type("javafx.scene.shape.TriangleMesh");
+VLineTo                                = Java.type("javafx.scene.shape.VLineTo");
+VLineToBuilder                         = Java.type("javafx.scene.shape.VLineToBuilder");
+SnapshotParameters                     = Java.type("javafx.scene.SnapshotParameters");
+SnapshotParametersBuilder              = Java.type("javafx.scene.SnapshotParametersBuilder");
+SnapshotResult                         = Java.type("javafx.scene.SnapshotResult");
+SubScene                               = Java.type("javafx.scene.SubScene");
+SubSceneBuilder                        = Java.type("javafx.scene.SubSceneBuilder");
+Font                                   = Java.type("javafx.scene.text.Font");
+FontBuilder                            = Java.type("javafx.scene.text.FontBuilder");
+FontPosture                            = Java.type("javafx.scene.text.FontPosture");
+FontSmoothingType                      = Java.type("javafx.scene.text.FontSmoothingType");
+FontWeight                             = Java.type("javafx.scene.text.FontWeight");
+Text                                   = Java.type("javafx.scene.text.Text");
+TextAlignment                          = Java.type("javafx.scene.text.TextAlignment");
+TextBoundsType                         = Java.type("javafx.scene.text.TextBoundsType");
+TextBuilder                            = Java.type("javafx.scene.text.TextBuilder");
+TextFlow                               = Java.type("javafx.scene.text.TextFlow");
+TextFlowBuilder                        = Java.type("javafx.scene.text.TextFlowBuilder");
+Affine                                 = Java.type("javafx.scene.transform.Affine");
+AffineBuilder                          = Java.type("javafx.scene.transform.AffineBuilder");
+MatrixType                             = Java.type("javafx.scene.transform.MatrixType");
+NonInvertibleTransformException        = Java.type("javafx.scene.transform.NonInvertibleTransformException");
+Rotate                                 = Java.type("javafx.scene.transform.Rotate");
+RotateBuilder                          = Java.type("javafx.scene.transform.RotateBuilder");
+Scale                                  = Java.type("javafx.scene.transform.Scale");
+ScaleBuilder                           = Java.type("javafx.scene.transform.ScaleBuilder");
+Shear                                  = Java.type("javafx.scene.transform.Shear");
+ShearBuilder                           = Java.type("javafx.scene.transform.ShearBuilder");
+Transform                              = Java.type("javafx.scene.transform.Transform");
+TransformBuilder                       = Java.type("javafx.scene.transform.TransformBuilder");
+TransformChangedEvent                  = Java.type("javafx.scene.transform.TransformChangedEvent");
+Translate                              = Java.type("javafx.scene.transform.Translate");
+TranslateBuilder                       = Java.type("javafx.scene.transform.TranslateBuilder");
+DirectoryChooser                       = Java.type("javafx.stage.DirectoryChooser");
+DirectoryChooserBuilder                = Java.type("javafx.stage.DirectoryChooserBuilder");
+FileChooser                            = Java.type("javafx.stage.FileChooser");
+FileChooser$ExtensionFilter            = Java.type("javafx.stage.FileChooser$ExtensionFilter");
+FileChooserBuilder                     = Java.type("javafx.stage.FileChooserBuilder");
+Modality                               = Java.type("javafx.stage.Modality");
+Popup                                  = Java.type("javafx.stage.Popup");
+PopupBuilder                           = Java.type("javafx.stage.PopupBuilder");
+PopupWindow                            = Java.type("javafx.stage.PopupWindow");
+PopupWindowBuilder                     = Java.type("javafx.stage.PopupWindowBuilder");
+Screen                                 = Java.type("javafx.stage.Screen");
+//Stage                                  = Java.type("javafx.stage.Stage");
+StageBuilder                           = Java.type("javafx.stage.StageBuilder");
+StageStyle                             = Java.type("javafx.stage.StageStyle");
+Window                                 = Java.type("javafx.stage.Window");
+WindowBuilder                          = Java.type("javafx.stage.WindowBuilder");
+WindowEvent                            = Java.type("javafx.stage.WindowEvent");
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/media.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+AudioClip             = Java.type("javafx.scene.media.AudioClip");
+AudioClipBuilder      = Java.type("javafx.scene.media.AudioClipBuilder");
+AudioEqualizer        = Java.type("javafx.scene.media.AudioEqualizer");
+AudioSpectrumListener = Java.type("javafx.scene.media.AudioSpectrumListener");
+AudioTrack            = Java.type("javafx.scene.media.AudioTrack");
+EqualizerBand         = Java.type("javafx.scene.media.EqualizerBand");
+Media                 = Java.type("javafx.scene.media.Media");
+MediaBuilder          = Java.type("javafx.scene.media.MediaBuilder");
+MediaErrorEvent       = Java.type("javafx.scene.media.MediaErrorEvent");
+MediaException        = Java.type("javafx.scene.media.MediaException");
+MediaException$Type   = Java.type("javafx.scene.media.MediaException$Type");
+MediaMarkerEvent      = Java.type("javafx.scene.media.MediaMarkerEvent");
+MediaPlayer           = Java.type("javafx.scene.media.MediaPlayer");
+MediaPlayer$Status    = Java.type("javafx.scene.media.MediaPlayer$Status");
+MediaPlayerBuilder    = Java.type("javafx.scene.media.MediaPlayerBuilder");
+MediaView             = Java.type("javafx.scene.media.MediaView");
+MediaViewBuilder      = Java.type("javafx.scene.media.MediaViewBuilder");
+SubtitleTrack         = Java.type("javafx.scene.media.SubtitleTrack");
+Track                 = Java.type("javafx.scene.media.Track");
+VideoTrack            = Java.type("javafx.scene.media.VideoTrack");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swing.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+JFXPanel        = Java.type("javafx.embed.swing.JFXPanel");
+JFXPanelBuilder = Java.type("javafx.embed.swing.JFXPanelBuilder");
+SwingFXUtils    = Java.type("javafx.embed.swing.SwingFXUtils");
+SwingNode       = Java.type("javafx.embed.swing.SwingNode");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/swt.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+CustomTransfer        = Java.type("javafx.embed.swt.CustomTransfer");
+CustomTransferBuilder = Java.type("javafx.embed.swt.CustomTransferBuilder");
+FXCanvas              = Java.type("javafx.embed.swt.FXCanvas");
+SWTFXUtils            = Java.type("javafx.embed.swt.SWTFXUtils");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/fx/web.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+HTMLEditor        = Java.type("javafx.scene.web.HTMLEditor");
+HTMLEditorBuilder = Java.type("javafx.scene.web.HTMLEditorBuilder");
+PopupFeatures     = Java.type("javafx.scene.web.PopupFeatures");
+PromptData        = Java.type("javafx.scene.web.PromptData");
+PromptDataBuilder = Java.type("javafx.scene.web.PromptDataBuilder");
+WebEngine         = Java.type("javafx.scene.web.WebEngine");
+WebEngineBuilder  = Java.type("javafx.scene.web.WebEngineBuilder");
+WebEvent          = Java.type("javafx.scene.web.WebEvent");
+WebHistory        = Java.type("javafx.scene.web.WebHistory");
+WebView           = Java.type("javafx.scene.web.WebView");
+WebViewBuilder    = Java.type("javafx.scene.web.WebViewBuilder");
--- a/nashorn/src/jdk/nashorn/tools/Shell.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/src/jdk/nashorn/tools/Shell.java	Thu May 16 11:47:51 2013 +0100
@@ -42,9 +42,12 @@
 import jdk.nashorn.api.scripting.NashornException;
 import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.debug.ASTWriter;
+import jdk.nashorn.internal.ir.debug.PrintVisitor;
 import jdk.nashorn.internal.parser.Parser;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ErrorManager;
+import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -168,7 +171,11 @@
             return compileScripts(context, global, files);
         }
 
-        return runScripts(context, global, files);
+        if (env._fx) {
+            return runFXScripts(context, global, files);
+        } else {
+            return runScripts(context, global, files);
+        }
     }
 
     /**
@@ -254,6 +261,14 @@
                     return COMPILATION_ERROR;
                 }
 
+                if (env._print_ast) {
+                    context.getErr().println(new ASTWriter(functionNode));
+                }
+
+                if (env._print_parse) {
+                    context.getErr().println(new PrintVisitor(functionNode));
+                }
+
                 //null - pass no code installer - this is compile only
                 new Compiler(env, functionNode).compile();
             }
@@ -318,6 +333,46 @@
     }
 
     /**
+     * Runs launches "fx:bootstrap.js" with the given JavaScript files provided
+     * as arguments.
+     *
+     * @param context the nashorn context
+     * @param global the global scope
+     * @param files the list of script files to provide
+     *
+     * @return error code
+     * @throws IOException when any script file read results in I/O error
+     */
+    private int runFXScripts(final Context context, final ScriptObject global, final List<String> files) throws IOException {
+        final ScriptObject oldGlobal = Context.getGlobal();
+        final boolean globalChanged = (oldGlobal != global);
+        try {
+            if (globalChanged) {
+                Context.setGlobal(global);
+            }
+
+            global.addOwnProperty("$GLOBAL", Property.NOT_ENUMERABLE, global);
+            global.addOwnProperty("$SCRIPTS", Property.NOT_ENUMERABLE, files);
+            context.load(global, "fx:bootstrap.js");
+        } catch (final NashornException e) {
+            context.getErrorManager().error(e.toString());
+            if (context.getEnv()._dump_on_error) {
+                e.printStackTrace(context.getErr());
+            }
+
+            return RUNTIME_ERROR;
+        } finally {
+            context.getOut().flush();
+            context.getErr().flush();
+            if (globalChanged) {
+                Context.setGlobal(oldGlobal);
+            }
+        }
+
+        return SUCCESS;
+    }
+
+    /**
      * Hook to ScriptFunction "apply". A performance metering shell may
      * introduce enter/exit timing here.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/examples/int-micro.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+function bench(name, func) {
+    var start = Date.now();
+    for (var iter = 0; iter < 5000000; iter++) {
+        func();
+    }
+    print(name + "\t" + (Date.now() - start));
+}
+
+function uint32(value) {
+    return function() {
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+        value >>> 0;
+    };
+}
+
+function int32(value) {
+    return function() {
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+        value >> 0;
+    };
+}
+
+print("\nToUint32");
+for (var i = 1; i < 3; i++) {
+    bench("infinity      ", uint32(Infinity));
+    bench("infinity neg  ", uint32(-Infinity));
+    bench("nan           ", uint32(NaN));
+    bench("small         ", uint32(1));
+    bench("small neg     ", uint32(-1));
+    bench("small frac    ", uint32(1.5));
+    bench("small neg frac", uint32(-1.5));
+    bench("large         ", uint32(9223372036854775807));
+    bench("large neg     ", uint32(-9223372036854775808));
+}
+
+print("\nToInt32");
+for (var i = 1; i < 3; i++) {
+    bench("infinity      ", int32(Infinity));
+    bench("infinity neg  ", int32(-Infinity));
+    bench("nan           ", int32(NaN));
+    bench("small         ", int32(1));
+    bench("small neg     ", int32(-1));
+    bench("small frac    ", int32(1.5));
+    bench("small neg frac", int32(-1.5));
+    bench("large         ", int32(9223372036854775807));
+    bench("large neg     ", int32(-9223372036854775808));
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8008238.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8008238: Labeled break in finally causes stack overflow in Node copy
+ *
+ * @test
+ * @run
+ */
+
+a: try {
+} finally {
+    break a;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8008814-3.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * NASHORN-8008814: it's not a compile time error to have a nested strict function declaration when the outer one is not strict
+ *
+ * @test
+ * @run
+ */
+
+function f() {
+  if(true) {
+    function g() {
+      "use strict";
+      print("g invoked!")
+    }
+  }
+  g()
+}
+f()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8008814-3.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,1 @@
+g invoked!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8008814-4.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * NASHORN-8008814: it's not a compile time error to have a nested function declaration when warnings are reported
+ *
+ * @option --function-statement-warning
+ * @test
+ * @run/ignore-std-error
+ */
+
+function f() {
+  if(true) {
+    function g() {
+      print("g invoked!")
+    }
+  }
+  g()
+}
+f()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8008814-4.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,1 @@
+g invoked!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8011578.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8011578 : -Dnashorn.unstable.relink.threshold=1 causes tests to fail.
+ *
+ * @test
+ * @option -Dnashorn.unstable.relink.threshold=1
+ * @run
+ */
+
+load(__DIR__ + "NASHORN-296.js");
+load(__DIR__ + "NASHORN-691.js");
+load(__DIR__ + "calllink.js");
+load(__DIR__ + "nosuchproperty.js");
+
+__noSuchProperty__ = function(x) {
+    print(x);
+    return x;
+}
+
+print(this["find"]);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8011578.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,22 @@
+o.foo = 33
+o.foo = 44
+o.foo = 3
+o.foo = hello
+obj1.func called
+obj2.func called
+no such method: func
+obj4's prototype func called
+MyConstructor.prototype.func
+MyConstructor.prototype.func
+obj1.func called
+obj2.func called
+new obj3.func called
+new obj4.func called
+all new MyConstructor.prototype.func
+all new MyConstructor.prototype.func
+obj.__noSuchProperty__ for foo
+new obj.__noSuchProperty__ for foo
+proto.__noSuchProperty__ for foo
+new proto.__noSuchProperty__ for foo
+find
+find
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012240.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012240: Array.prototype.map.call({length: -1, get 0(){throw 0}}, function(){}).length does not throw error
+ *
+ * @test
+ * @run
+ */
+
+var in_getter_for_0 = false;
+
+try {
+    Array.prototype.map.call(
+        {
+            length: -1, 
+            get 0() {
+                in_getter_for_0 = true;
+                throw 0;
+            }
+        }, 
+    function(){}).length;
+} catch (e) {
+    if (e !== 0 || !in_getter_for_0) {
+       fail("should have thrown error from getter for '0'th element");
+    }
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012334.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012334: ToUint32, ToInt32, and ToUint16 don't conform to spec
+ *
+ * @test
+ * @run
+ */
+
+
+function test(val) {
+    print(val | 0);
+    print(val >> 0);
+    print(val >>> 0);
+    print(1 >>> val);
+    print(parseInt("10", val));
+}
+
+test(0);
+test(-0);
+test('Infinity');
+test('+Infinity');
+test('-Infinity');
+test(Number.POSITIVE_INFINITY);
+test(Number.NEGATIVE_INFINITY);
+test(Number.NaN);
+test(Number.MIN_VALUE);
+test(-Number.MIN_VALUE);
+test(1);
+test(-1);
+test(0.1);
+test(-0.1);
+test(1.1);
+test(-1.1);
+test(9223372036854775807);
+test(-9223372036854775808);
+test('9223372036854775807');
+test('-9223372036854775808');
+test(2147483647);
+test(2147483648);
+test(2147483649);
+test(-2147483647);
+test(-2147483648);
+test(-2147483649);
+test(4294967295);
+test(4294967296);
+test(4294967297);
+test(-4294967295);
+test(-4294967296);
+test(-4294967297);
+test(1e23);
+test(-1e23);
+test(1e24);
+test(-1e24);
+test(1e25);
+test(-1e25);
+test(1e26);
+test(-1e26);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012334.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,200 @@
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+1
+1
+1
+0
+NaN
+-1
+-1
+4294967295
+0
+NaN
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+1
+1
+1
+0
+NaN
+-1
+-1
+4294967295
+0
+NaN
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
+2147483647
+2147483647
+2147483647
+0
+NaN
+-2147483648
+-2147483648
+2147483648
+1
+NaN
+-2147483647
+-2147483647
+2147483649
+0
+NaN
+-2147483647
+-2147483647
+2147483649
+0
+NaN
+-2147483648
+-2147483648
+2147483648
+1
+NaN
+2147483647
+2147483647
+2147483647
+0
+NaN
+-1
+-1
+4294967295
+0
+NaN
+0
+0
+0
+1
+10
+1
+1
+1
+0
+NaN
+1
+1
+1
+0
+NaN
+0
+0
+0
+1
+10
+-1
+-1
+4294967295
+0
+NaN
+-167772160
+-167772160
+4127195136
+1
+NaN
+167772160
+167772160
+167772160
+1
+NaN
+-1610612736
+-1610612736
+2684354560
+1
+NaN
+1610612736
+1610612736
+1610612736
+1
+NaN
+-2147483648
+-2147483648
+2147483648
+1
+NaN
+-2147483648
+-2147483648
+2147483648
+1
+NaN
+0
+0
+0
+1
+10
+0
+0
+0
+1
+10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012457.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012457: Function.prototype.apply should accept any array-like argument for function arguments
+ *
+ * @test
+ * @run
+ */
+
+// no exception for these
+Function().apply(null, {length: null})
+Function().apply(null, {length: 0.1})
+
+// getter should be called
+var getter_0_called = false;
+
+Function().apply(null, 
+    Object.defineProperty([],"0",
+        {  get: function(){ getter_0_called = true; return 0 }
+    })
+);
+
+if (! getter_0_called) {
+    fail("getter for '0' of arguments array not called");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012460.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012460: RegExp regression
+ *
+ * @test
+ * @run
+ */
+
+
+var semver = "\\s*[v=]*\\s*([0-9]+)" // major
+        + "\\.([0-9]+)" // minor
+        + "\\.([0-9]+)" // patch
+        + "(-[0-9]+-?)?" // build
+        + "([a-zA-Z-+][a-zA-Z0-9-\.:]*)?" // tag
+    , exprComparator = "^((<|>)?=?)\s*("+semver+")$|^$";
+var validComparator = new RegExp("^"+exprComparator+"$");
+
+
+print(exprComparator);
+print(">=0.6.0-".match(validComparator));
+print("=0.6.0-".match(validComparator));
+print("0.6.0-".match(validComparator));
+print("<=0.6.0-".match(validComparator));
+print(">=0.6.0-a:b-c.d".match(validComparator));
+print("=0.6.0-a:b-c.d".match(validComparator));
+print("0.6.0+a:b-c.d".match(validComparator));
+print("<=0.6.0+a:b-c.d".match(validComparator));
+
+print(/[a-zA-Z-+]/.exec("a"));
+print(/[a-zA-Z-+]/.exec("b"));
+print(/[a-zA-Z-+]/.exec("y"));
+print(/[a-zA-Z-+]/.exec("z"));
+print(/[a-zA-Z-+]/.exec("B"));
+print(/[a-zA-Z-+]/.exec("Y"));
+print(/[a-zA-Z-+]/.exec("Z"));
+print(/[a-zA-Z-+]/.exec("-"));
+print(/[a-zA-Z-+]/.exec("+"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012460.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,18 @@
+^((<|>)?=?)s*(\s*[v=]*\s*([0-9]+)\.([0-9]+)\.([0-9]+)(-[0-9]+-?)?([a-zA-Z-+][a-zA-Z0-9-.:]*)?)$|^$
+>=0.6.0-,>=,>,0.6.0-,0,6,0,,-
+=0.6.0-,=,,0.6.0-,0,6,0,,-
+0.6.0-,,,0.6.0-,0,6,0,,-
+<=0.6.0-,<=,<,0.6.0-,0,6,0,,-
+>=0.6.0-a:b-c.d,>=,>,0.6.0-a:b-c.d,0,6,0,,-a:b-c.d
+=0.6.0-a:b-c.d,=,,0.6.0-a:b-c.d,0,6,0,,-a:b-c.d
+0.6.0+a:b-c.d,,,0.6.0+a:b-c.d,0,6,0,,+a:b-c.d
+<=0.6.0+a:b-c.d,<=,<,0.6.0+a:b-c.d,0,6,0,,+a:b-c.d
+a
+b
+y
+z
+B
+Y
+Z
+-
++
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012462.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012462: Date.prototype.toJSON does not handle non-Date 'this' as per the spec.
+ *
+ * @test
+ * @run
+ */
+
+var toJSON = Date.prototype.toJSON;
+
+function checkJSON(value, expected) {
+    var res = toJSON.call({
+        valueOf: function() { return value; },
+        toISOString: function() { return value; }
+    });
+
+    if (res !== expected) {
+        fail("Date.prototype.toJSON does not work for non-Date 'this'");
+    }
+}
+
+checkJSON(NaN, null);
+checkJSON(-Infinity, null);
+checkJSON(Infinity, null);
+checkJSON("foo", "foo");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012931.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8012931: NativeDate.safeToString() throws RangeError for invalid date
+ *
+ * @test
+ * @run
+ */
+
+var d = new Date(NaN);
+d.toString = Number.prototype.toString;
+
+try {
+    d.toString();
+} catch(e) {
+    print(e);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8012931.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,1 @@
+TypeError: [Date Invalid Date] is not a Number
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013131.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013131: Various compatibility issues in String.prototype.split()
+ *
+ * @test
+ * @run
+ */
+
+
+// Make sure limit is honored with undefined/empty separator
+print(JSON.stringify("aa".split(undefined, 0)));
+print(JSON.stringify("abc".split("", 1)));
+
+// Make sure limit is honored with capture groups
+print(JSON.stringify("aa".split(/(a)/, 1)));
+print(JSON.stringify("aa".split(/(a)/, 2)));
+print(JSON.stringify("aa".split(/((a))/, 1)));
+print(JSON.stringify("aa".split(/((a))/, 2)));
+
+// Empty capture group at end of string should be ignored
+print(JSON.stringify("aaa".split(/((?:))/)));
+
+// Tests below are to make sure that split does not read or write lastIndex property
+var r = /a/;
+r.lastIndex = {
+    valueOf: function(){throw 2}
+};
+print(JSON.stringify("aa".split(r)));
+
+r = /a/g;
+r.lastIndex = 100;
+print(JSON.stringify("aa".split(r)));
+print(r.lastIndex);
+
+r = /((?:))/g;
+r.lastIndex = 100;
+print(JSON.stringify("aaa".split(r)));
+print(r.lastIndex);
+
+// Make sure lastIndex is not updated on non-global regexp
+r = /a/;
+r.lastIndex = 100;
+print(JSON.stringify(r.exec("aaa")));
+print(r.lastIndex);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013131.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,14 @@
+[]
+["a"]
+[""]
+["","a"]
+[""]
+["","a"]
+["a","","a","","a"]
+["","",""]
+["","",""]
+100
+["a","","a","","a"]
+100
+["a"]
+100
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013167.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013167: Vararg constructor was not found
+ *
+ * @test
+ * @run
+ */
+
+var x = new Packages.jdk.nashorn.test.models.VarArgConstructor(1, false, "a", "b", "c")
+print(x.indicator)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013167.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,1 @@
+vararg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013325.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013325: function named 'arguments' should still access arguments object within itself.
+ * Its parent should however see the function and not an arguments object.
+ *
+ * @test
+ * @run
+ */
+
+function x() {
+  // x doesn't see an arguments object as it has a nested function with that name
+  // so it'll invoke the function.
+  arguments("a", "b", "c");
+  
+  function arguments(x, y, z) {
+      // The function 'arguments' OTOH can't see itself; if it uses the 
+      // identifier 'arguments', it'll see its own arguments object.
+      print(arguments)
+      print(x + " " + y + " " + z)
+  }
+}
+x()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013325.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,2 @@
+[object Arguments]
+a b c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013337.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013337: Issues with Date.prototype's get, set functions 
+ *
+ * @test
+ * @option -timezone=Asia/Calcutta
+ * @run
+ */
+
+function check(str) {
+    print(str + " = " + eval(str));
+}
+
+check('new Date(NaN).setFullYear(NaN)');
+check('new Date(0).setYear(70)');
+check('new Date(0).setYear(NaN)');
+check('new Date(NaN).setYear(70)');
+check('new Date(NaN).getTimezoneOffset()');
+
+function checkGetterCalled(func) {
+    var getterCalled = false;
+
+    new Date(NaN)[func]( { valueOf: function() { getterCalled = true } } );
+
+    if (getterCalled) {
+       print("Date.prototype." + func + " calls valueOf on arg");
+    }
+}
+
+checkGetterCalled("setMilliseconds");
+checkGetterCalled("setUTCMilliseconds");
+checkGetterCalled("setSeconds");
+checkGetterCalled("setUTCSeconds");
+checkGetterCalled("setMinutes");
+checkGetterCalled("setUTCMinutes");
+checkGetterCalled("setHours");
+checkGetterCalled("setUTCHours");
+checkGetterCalled("setDate");
+checkGetterCalled("setUTCDate");
+checkGetterCalled("setMonth");
+checkGetterCalled("setUTCMonth");
+
+try {
+    Date.prototype.setTime.call({}, { valueOf: function() { throw "err" } }) 
+} catch (e) {
+    if (! (e instanceof TypeError)) {
+        fail("TypeError expected, got " + e);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013337.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,17 @@
+new Date(NaN).setFullYear(NaN) = NaN
+new Date(0).setYear(70) = 0
+new Date(0).setYear(NaN) = NaN
+new Date(NaN).setYear(70) = -19800000
+new Date(NaN).getTimezoneOffset() = NaN
+Date.prototype.setMilliseconds calls valueOf on arg
+Date.prototype.setUTCMilliseconds calls valueOf on arg
+Date.prototype.setSeconds calls valueOf on arg
+Date.prototype.setUTCSeconds calls valueOf on arg
+Date.prototype.setMinutes calls valueOf on arg
+Date.prototype.setUTCMinutes calls valueOf on arg
+Date.prototype.setHours calls valueOf on arg
+Date.prototype.setUTCHours calls valueOf on arg
+Date.prototype.setDate calls valueOf on arg
+Date.prototype.setUTCDate calls valueOf on arg
+Date.prototype.setMonth calls valueOf on arg
+Date.prototype.setUTCMonth calls valueOf on arg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013444.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8013444: JSON.parse does not invoke "reviver" callback as per spec.
+ *
+ * @test
+ * @run
+ */
+
+
+var type = typeof JSON.parse('{}',function(){})
+print("type is " + type);
+
+var obj = JSON.parse('{"name": "nashorn"}', 
+    function(k, v) {
+        if (k === "") return v;
+        return v.toUpperCase();
+    });
+print(JSON.stringify(obj))
+
+var array = 
+  JSON.parse("[1, 3, 5, 7, 9, 11]",
+   function(k, v) {
+      if (k === "") return v;
+      return v*2;
+   }
+ );
+print(array)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8013444.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,3 @@
+type is undefined
+{"name":"NASHORN"}
+2,6,10,14,18,22
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/try2.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Try throw test - nest finally
+ *
+ * @test
+ * @run 
+ */
+
+function f() {
+    print("a");
+    try {
+	print("b");
+    } finally {
+	print("c");
+	try {
+	    print("d");
+	} finally {
+	    print("e");
+	}
+	print("f");
+    }
+    print("g");
+}
+
+f();
+
+print("done");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/try2.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,8 @@
+a
+b
+c
+d
+e
+f
+g
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8008814-1.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * NASHORN-8008814: it's a compile time error to have a nested function declaration when there's an option to treat it as an error
+ *
+ * @option --function-statement-error
+ * @test/compile-error
+ */
+
+if(true) {
+  function g() {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8008814-1.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,3 @@
+test/script/error/JDK-8008814-1.js:32:2 Function declarations can only occur at program or function body level. You should use a function expression here instead.
+  function g() {
+  ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8008814-2.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * NASHORN-8008814: it's a compile time error to have a nested function declaration in strict mode
+ *
+ * @test/compile-error
+ */
+
+"use strict";
+if(true) {
+  function g() {
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/error/JDK-8008814-2.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,3 @@
+test/script/error/JDK-8008814-2.js:32:2 In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead.
+  function g() {
+  ^
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/logcoverage.js	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * mh_coverage.js
+ * Screen scrape various logs to ensure that we cover enough functionality, 
+ * e.g. method handle instrumentation
+ *
+ * @test
+ * @run
+ */
+
+/*
+ * creates new script engine initialized with given options and
+ * runs given code on it. Returns standard output captured.
+ */
+
+function runScriptEngine(opts, name) {
+    var imports = new JavaImporter(
+        Packages.jdk.nashorn.api.scripting,
+        java.io, java.lang, java.util);
+
+    with(imports) {
+        var fac = new NashornScriptEngineFactory();
+        // get current System.err
+        var oldErr = System.err;
+	var oldOut = System.out;
+        var baosErr = new ByteArrayOutputStream();
+        var newErr = new PrintStream(baosErr);
+        var baosOut = new ByteArrayOutputStream();
+	var newOut = new PrintStream(baosOut);
+        try {
+            // set new standard err
+            System.setErr(newErr);
+            System.setOut(newOut);
+            var strType = Java.type("java.lang.String");
+            var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType));
+	    var reader = new java.io.FileReader(name);
+            engine.eval(reader);
+            newErr.flush();
+	    newOut.flush();
+            return new java.lang.String(baosErr.toByteArray());
+        } finally {
+            // restore System.err to old value
+            System.setErr(oldErr);
+	    System.setOut(oldOut);
+        }
+    }
+}
+
+var str;
+
+var methodsCalled = [
+   'asCollector', 
+   'asType', 
+   'bindTo', 
+   'dropArguments', 
+   'explicitCastArguments', 
+   'filterArguments', 
+   'filterReturnValue', 
+   'findStatic', 
+   'findVirtual',  
+   'foldArguments', 
+   'getter', 
+   'guardWithTest', 
+   'insertArguments', 
+   'methodType', 
+   'setter'
+];
+
+function check(str, strs) {
+    for each (s in strs) {
+       if (s.indexOf(str) !== -1) {
+	   continue;
+       }
+       print(method + "not found");
+       return;
+    }
+    print("check ok!");
+}
+
+str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
+
+check(str, methodsCalled);
+check(str, ['return', 'get', 'set', '[fields]']);
+check(str, ['codegen']);
+
+print("hello, world!");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/logcoverage.js.EXPECTED	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,4 @@
+check ok!
+check ok!
+check ok!
+hello, world!
--- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java	Thu May 16 11:47:51 2013 +0100
@@ -55,7 +55,7 @@
  * Tests for JSR-223 script engine for Nashorn.
  *
  * @test
- * @build jdk.nashorn.api.scripting.Window jdk.nashorn.api.scripting.WindowEventHandler jdk.nashorn.api.scripting.ScriptEngineTest
+ * @build jdk.nashorn.api.scripting.Window jdk.nashorn.api.scripting.WindowEventHandler jdk.nashorn.api.scripting.VariableArityTestInterface jdk.nashorn.api.scripting.ScriptEngineTest
  * @run testng jdk.nashorn.api.scripting.ScriptEngineTest
  */
 public class ScriptEngineTest {
@@ -906,4 +906,26 @@
             fail(se.getMessage());
         }
     }
+
+    @Test
+    /**
+     * Tests whether invocation of a JavaScript method through a variable arity Java method will pass the vararg array.
+     * Both non-vararg and vararg JavaScript methods are tested.
+     * @throws ScriptException
+     */
+    public void variableArityInterfaceTest() throws ScriptException {
+        final ScriptEngineManager m = new ScriptEngineManager();
+        final ScriptEngine e = m.getEngineByName("nashorn");
+        e.eval(
+            "function test1(i, strings) {" +
+            "    return 'i == ' + i + ', strings instanceof java.lang.String[] == ' + (strings instanceof Java.type('java.lang.String[]')) + ', strings == ' + java.util.Arrays.toString(strings)" +
+            "}" +
+            "function test2() {" +
+            "    return 'arguments[0] == ' + arguments[0] + ', arguments[1] instanceof java.lang.String[] == ' + (arguments[1] instanceof Java.type('java.lang.String[]')) + ', arguments[1] == ' + java.util.Arrays.toString(arguments[1])" +
+            "}"
+        );
+        final VariableArityTestInterface itf = ((Invocable)e).getInterface(VariableArityTestInterface.class);
+        Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]");
+        Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]");
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/VariableArityTestInterface.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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.api.scripting;
+
+public interface VariableArityTestInterface {
+    public String test1(int i, String... strings);
+    public String test2(int i, String... strings);
+}
--- a/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/test/src/jdk/nashorn/internal/runtime/JSTypeTest.java	Thu May 16 11:47:51 2013 +0100
@@ -105,4 +105,89 @@
         // FIXME: add more number-to-string test cases
         // FIXME: add case for Object type (JSObject with getDefaultValue)
     }
+
+    /**
+     * Test of JSType.toUint32(double)
+     */
+    @Test
+    public void testToUint32() {
+        assertEquals(JSType.toUint32(+0.0), 0);
+        assertEquals(JSType.toUint32(-0.0), 0);
+        assertEquals(JSType.toUint32(Double.NaN), 0);
+        assertEquals(JSType.toUint32(Double.POSITIVE_INFINITY), 0);
+        assertEquals(JSType.toUint32(Double.NEGATIVE_INFINITY), 0);
+        assertEquals(JSType.toUint32(9223372036854775807.0d), 0);
+        assertEquals(JSType.toUint32(-9223372036854775807.0d), 0);
+        assertEquals(JSType.toUint32(1099511627776.0d), 0);
+        assertEquals(JSType.toUint32(-1099511627776.0d), 0);
+        assertEquals(JSType.toUint32(4294967295.0d), 4294967295l);
+        assertEquals(JSType.toUint32(4294967296.0d), 0);
+        assertEquals(JSType.toUint32(4294967297.0d), 1);
+        assertEquals(JSType.toUint32(-4294967295.0d), 1);
+        assertEquals(JSType.toUint32(-4294967296.0d), 0);
+        assertEquals(JSType.toUint32(-4294967297.0d), 4294967295l);
+        assertEquals(JSType.toUint32(4294967295.6d), 4294967295l);
+        assertEquals(JSType.toUint32(4294967296.6d), 0);
+        assertEquals(JSType.toUint32(4294967297.6d), 1);
+        assertEquals(JSType.toUint32(-4294967295.6d), 1);
+        assertEquals(JSType.toUint32(-4294967296.6d), 0);
+        assertEquals(JSType.toUint32(-4294967297.6d), 4294967295l);
+    }
+
+    /**
+     * Test of JSType.toInt32(double)
+     */
+    @Test
+    public void testToInt32() {
+        assertEquals(JSType.toInt32(+0.0), 0);
+        assertEquals(JSType.toInt32(-0.0), 0);
+        assertEquals(JSType.toInt32(Double.NaN), 0);
+        assertEquals(JSType.toInt32(Double.POSITIVE_INFINITY), 0);
+        assertEquals(JSType.toInt32(Double.NEGATIVE_INFINITY), 0);
+        assertEquals(JSType.toInt32(9223372036854775807.0d), 0);
+        assertEquals(JSType.toInt32(-9223372036854775807.0d), 0);
+        assertEquals(JSType.toInt32(1099511627776.0d), 0);
+        assertEquals(JSType.toInt32(-1099511627776.0d), 0);
+        assertEquals(JSType.toInt32(4294967295.0d), -1);
+        assertEquals(JSType.toInt32(4294967296.0d), 0);
+        assertEquals(JSType.toInt32(4294967297.0d), 1);
+        assertEquals(JSType.toInt32(-4294967295.0d), 1);
+        assertEquals(JSType.toInt32(-4294967296.0d), 0);
+        assertEquals(JSType.toInt32(-4294967297.d), -1);
+        assertEquals(JSType.toInt32(4294967295.6d), -1);
+        assertEquals(JSType.toInt32(4294967296.6d), 0);
+        assertEquals(JSType.toInt32(4294967297.6d), 1);
+        assertEquals(JSType.toInt32(-4294967295.6d), 1);
+        assertEquals(JSType.toInt32(-4294967296.6d), 0);
+        assertEquals(JSType.toInt32(-4294967297.6d), -1);
+    }
+
+    /**
+     * Test of JSType.toUint16(double)
+     */
+    @Test
+    public void testToUint16() {
+        assertEquals(JSType.toUint16(+0.0), 0);
+        assertEquals(JSType.toUint16(-0.0), 0);
+        assertEquals(JSType.toUint16(Double.NaN), 0);
+        assertEquals(JSType.toUint16(Double.POSITIVE_INFINITY), 0);
+        assertEquals(JSType.toUint16(Double.NEGATIVE_INFINITY), 0);
+        assertEquals(JSType.toUint16(9223372036854775807.0d), 0);
+        assertEquals(JSType.toUint16(-9223372036854775807.0d), 0);
+        assertEquals(JSType.toUint16(1099511627776.0d), 0);
+        assertEquals(JSType.toUint16(-1099511627776.0d), 0);
+        assertEquals(JSType.toUint16(4294967295.0d), 65535);
+        assertEquals(JSType.toUint16(4294967296.0d), 0);
+        assertEquals(JSType.toUint16(4294967297.0d), 1);
+        assertEquals(JSType.toUint16(-4294967295.0d), 1);
+        assertEquals(JSType.toUint16(-4294967296.0d), 0);
+        assertEquals(JSType.toUint16(-4294967297.0d), 65535);
+        assertEquals(JSType.toUint16(4294967295.6d), 65535);
+        assertEquals(JSType.toUint16(4294967296.6d), 0);
+        assertEquals(JSType.toUint16(4294967297.6d), 1);
+        assertEquals(JSType.toUint16(-4294967295.6d), 1);
+        assertEquals(JSType.toUint16(-4294967296.6d), 0);
+        assertEquals(JSType.toUint16(-4294967297.6d), 65535);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/test/models/VarArgConstructor.java	Thu May 16 11:47:51 2013 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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.test.models;
+
+import java.util.List;
+
+public class VarArgConstructor {
+    private final String indicator;
+
+    public VarArgConstructor(int x, boolean y, List<String> z) {
+        indicator = "non-vararg";
+    }
+
+    public VarArgConstructor(int x, boolean y, String... z) {
+        indicator = "vararg";
+    }
+
+    public String getIndicator() {
+        return indicator;
+    }
+}
--- a/nashorn/tools/fxshell/jdk/nashorn/tools/FXShell.java	Wed May 08 11:22:25 2013 +0100
+++ b/nashorn/tools/fxshell/jdk/nashorn/tools/FXShell.java	Thu May 16 11:47:51 2013 +0100
@@ -178,7 +178,7 @@
      *
      * @param path Path to UTF-8 encoded JavaScript file.
      *
-     * @return Last evalulation result (discarded.)
+     * @return Last evaluation result (discarded.)
      */
     private Object load(String path) {
         try {