Merge
diff --git a/.hgtags b/.hgtags
index 0204d6b..fc07f2d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -375,3 +375,6 @@
 e3b11296395b39bfeb3364f26c2ef77fa652e300 jdk-9+139
 785843878cf78d50cc2959ea2c5a4202bbe885b4 jdk-9+140
 a46b7d3867957a868a6cc8ee66c05079b883733a jdk-9+141
+d3f5d7311a1aec3152b17d75046d5d298245a0b4 jdk-9+142
+b4e57ead3fae4939b70dd345d1f6744a1dedfa21 jdk-9+143
+a7f21ee6ed30695a6de14e74035d2857a754f62b jdk-9+144
diff --git a/samples/dynalink/ArrayStreamLinkerExporter.java b/samples/dynalink/ArrayStreamLinkerExporter.java
index 309f1e6..348ef3f 100644
--- a/samples/dynalink/ArrayStreamLinkerExporter.java
+++ b/samples/dynalink/ArrayStreamLinkerExporter.java
@@ -38,9 +38,10 @@
 import java.util.stream.LongStream;
 import java.util.stream.Stream;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -104,9 +105,9 @@
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
                 final Operation op = desc.getOperation();
                 final Object name = NamedOperation.getName(op);
-                final boolean getProp = CompositeOperation.contains(
+                final boolean getProp = NamespaceOperation.contains(
                         NamedOperation.getBaseOperation(op),
-                        StandardOperation.GET_PROPERTY);
+                        StandardOperation.GET, StandardNamespace.PROPERTY);
                 if (getProp && "stream".equals(name)) {
                     return new GuardedInvocation(ARRAY_TO_STREAM,
                         Guards.isOfClass(self.getClass(), GUARD_TYPE));
diff --git a/samples/dynalink/BufferIndexingLinkerExporter.java b/samples/dynalink/BufferIndexingLinkerExporter.java
index 9f49a0c..8fb99c1 100644
--- a/samples/dynalink/BufferIndexingLinkerExporter.java
+++ b/samples/dynalink/BufferIndexingLinkerExporter.java
@@ -29,6 +29,11 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodType;
 import java.nio.Buffer;
@@ -42,10 +47,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
 import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
@@ -135,23 +140,6 @@
         IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE);
     }
 
-    // locate the first standard operation from the call descriptor
-    private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
-        final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
-        if (base instanceof StandardOperation) {
-            return (StandardOperation)base;
-        } else if (base instanceof CompositeOperation) {
-            final CompositeOperation cop = (CompositeOperation)base;
-            for(int i = 0; i < cop.getOperationCount(); ++i) {
-                final Operation op = cop.getOperation(i);
-                if (op instanceof StandardOperation) {
-                    return (StandardOperation)op;
-                }
-            }
-        }
-        return null;
-    }
-
     @Override
     public List<GuardingDynamicLinker> get() {
         final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -170,22 +158,25 @@
                 }
 
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
-                final StandardOperation op = getFirstStandardOperation(desc);
-                if (op == null) {
+                final Operation namedOp = desc.getOperation();
+                final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+                final Operation op = NamespaceOperation.getBaseOperation(namespaceOp);
+                final StandardNamespace ns = StandardNamespace.findFirst(namespaceOp);
+                if (ns == null) {
                     return null;
                 }
 
-                switch (op) {
-                    case GET_ELEMENT:
+                if (op == GET) {
+                    if (ns == ELEMENT) {
                         return linkGetElement(self);
-                    case SET_ELEMENT:
-                        return linkSetElement(self);
-                    case GET_PROPERTY: {
+                    } else if (ns == PROPERTY) {
                         final Object name = NamedOperation.getName(desc.getOperation());
                         if ("length".equals(name)) {
                             return linkLength();
                         }
                     }
+                } else if (op == SET && ns == ELEMENT) {
+                    return linkSetElement(self);
                 }
 
                 return null;
diff --git a/samples/dynalink/DOMLinkerExporter.java b/samples/dynalink/DOMLinkerExporter.java
index 7724fd5..c544c9b 100644
--- a/samples/dynalink/DOMLinkerExporter.java
+++ b/samples/dynalink/DOMLinkerExporter.java
@@ -35,9 +35,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -132,9 +133,9 @@
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
                 final Operation op = desc.getOperation();
                 final Object name = NamedOperation.getName(op);
-                final boolean getProp = CompositeOperation.contains(
+                final boolean getProp = NamespaceOperation.contains(
                         NamedOperation.getBaseOperation(op),
-                        StandardOperation.GET_PROPERTY);
+                        StandardOperation.GET, StandardNamespace.PROPERTY);
                 if (getProp && name instanceof String) {
                     final String nameStr = (String)name;
 
diff --git a/samples/dynalink/MissingMethodLinkerExporter.java b/samples/dynalink/MissingMethodLinkerExporter.java
index e68b8d7..2ebb78b 100644
--- a/samples/dynalink/MissingMethodLinkerExporter.java
+++ b/samples/dynalink/MissingMethodLinkerExporter.java
@@ -35,9 +35,10 @@
 import java.util.ArrayList;
 import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.BeansLinker;
 import jdk.dynalink.linker.GuardedInvocation;
@@ -99,23 +100,6 @@
             "getName", MethodType.methodType(String.class));
     }
 
-    // locate the first standard operation from the call descriptor
-    private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
-        final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
-        if (base instanceof StandardOperation) {
-            return (StandardOperation)base;
-        } else if (base instanceof CompositeOperation) {
-            final CompositeOperation cop = (CompositeOperation)base;
-            for(int i = 0; i < cop.getOperationCount(); ++i) {
-                final Operation op = cop.getOperation(i);
-                if (op instanceof StandardOperation) {
-                    return (StandardOperation)op;
-                }
-            }
-        }
-        return null;
-    }
-
     @Override
     public List<GuardingDynamicLinker> get() {
         final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -140,8 +124,12 @@
                 // we return that method object. If not, we return a MissingMethod object.
                 if (self instanceof MissingMethodHandler) {
                     // Check if this is a named GET_METHOD first.
-                    final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD;
-                    final Object name = NamedOperation.getName(desc.getOperation());
+                    final Operation namedOp = desc.getOperation();
+                    final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+                    final Operation op = NamespaceOperation.getBaseOperation(namespaceOp);
+
+                    final boolean isGetMethod = op == StandardOperation.GET && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
+                    final Object name = NamedOperation.getName(namedOp);
                     if (isGetMethod && name instanceof String) {
                         final GuardingDynamicLinker javaLinker = beansLinker.getLinkerForClass(self.getClass());
                         GuardedInvocation inv;
@@ -166,7 +154,7 @@
                 } else if (self instanceof MissingMethod) {
                     // This is step (2). We call MissingMethodHandler.doesNotUnderstand here
                     // Check if this is this a CALL first.
-                    final boolean isCall = getFirstStandardOperation(desc) == StandardOperation.CALL;
+                    final boolean isCall = NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.CALL;
                     if (isCall) {
                         MethodHandle mh = DOES_NOT_UNDERSTAND;
 
diff --git a/samples/dynalink/UnderscoreNameLinkerExporter.java b/samples/dynalink/UnderscoreNameLinkerExporter.java
index 6025183..fe60aae 100644
--- a/samples/dynalink/UnderscoreNameLinkerExporter.java
+++ b/samples/dynalink/UnderscoreNameLinkerExporter.java
@@ -34,9 +34,10 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -68,23 +69,6 @@
         return buf.toString();
     }
 
-    // locate the first standard operation from the call descriptor
-    private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
-        final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
-        if (base instanceof StandardOperation) {
-            return (StandardOperation)base;
-        } else if (base instanceof CompositeOperation) {
-            final CompositeOperation cop = (CompositeOperation)base;
-            for(int i = 0; i < cop.getOperationCount(); ++i) {
-                final Operation op = cop.getOperation(i);
-                if (op instanceof StandardOperation) {
-                    return (StandardOperation)op;
-                }
-            }
-        }
-        return null;
-    }
-
     @Override
     public List<GuardingDynamicLinker> get() {
         final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -92,12 +76,14 @@
             @Override
             public GuardedInvocation getGuardedInvocation(final LinkRequest request,
                 final LinkerServices linkerServices) throws Exception {
-                final Object self = request.getReceiver();
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
                 final Operation op = desc.getOperation();
                 final Object name = NamedOperation.getName(op);
+                final Operation namespaceOp = NamedOperation.getBaseOperation(op);
                 // is this a named GET_METHOD?
-                final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD;
+                final boolean isGetMethod =
+                        NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
+                        && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
                 if (isGetMethod && name instanceof String) {
                     final String str = (String)name;
                     if (str.indexOf('_') == -1) {
@@ -106,13 +92,9 @@
 
                     final String nameStr = translateToCamelCase(str);
                     // create a new call descriptor to use translated name
-                    final CallSiteDescriptor newDesc = new CallSiteDescriptor(
-                        desc.getLookup(),
-                        new NamedOperation(NamedOperation.getBaseOperation(op), nameStr),
-                        desc.getMethodType());
+                    final CallSiteDescriptor newDesc = desc.changeOperation(((NamedOperation)op).changeName(nameStr));
                     // create a new Link request to link the call site with translated name
-                    final LinkRequest newRequest = new SimpleLinkRequest(newDesc,
-                        request.isCallSiteUnstable(), request.getArguments());
+                    final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
                     // return guarded invocation linking the translated request
                     return linkerServices.getGuardedInvocation(newRequest);
                 }
diff --git a/samples/dynalink/underscore_linker.js b/samples/dynalink/underscore_linker.js
index 98acd9e..82ad554 100644
--- a/samples/dynalink/underscore_linker.js
+++ b/samples/dynalink/underscore_linker.js
@@ -46,5 +46,6 @@
 // but make sure classpath points to the pluggable linker jar!
 
 `jjs -cp underscore_linker.jar underscore.js`
+print($ERR)
 print($OUT)
 
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
index 96a8269..e5ada58 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
@@ -83,9 +83,11 @@
 
 package jdk.dynalink;
 
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
 import java.util.Objects;
+import java.util.function.Supplier;
 
 /**
  * Call site descriptors contain all the information necessary for linking a
@@ -148,44 +150,82 @@
     }
 
     /**
-     * Creates a new call site descriptor from this descriptor, which is
-     * identical to this, except it changes the method type. Invokes
-     * {@link #changeMethodTypeInternal(MethodType)} and checks that it returns
-     * a descriptor of the same class as this descriptor.
+     * Finds or creates a call site descriptor that only differs in its
+     * method type from this descriptor.
+     * Invokes {@link #changeMethodTypeInternal(MethodType)}.
      *
      * @param newMethodType the new method type
-     * @return a new call site descriptor, with the method type changed.
-     * @throws RuntimeException if {@link #changeMethodTypeInternal(MethodType)}
-     * returned a descriptor of different class than this object.
-     * @throws NullPointerException if {@link #changeMethodTypeInternal(MethodType)}
-     * returned null.
+     * @return a call site descriptor with changed method type.
+     * @throws NullPointerException if {@code newMethodType} is null.
      */
     public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
-        final CallSiteDescriptor changed = Objects.requireNonNull(
-                changeMethodTypeInternal(newMethodType),
-                "changeMethodTypeInternal() must not return null.");
+        final CallSiteDescriptor changed = changeMethodTypeInternal(newMethodType);
 
-        if (getClass() != changed.getClass()) {
-            throw new RuntimeException(
-                    "changeMethodTypeInternal() must return an object of the same class it is invoked on.");
+        if (getClass() != CallSiteDescriptor.class) {
+            assertChangeInvariants(changed, "changeMethodTypeInternal");
+            alwaysAssert(operation == changed.operation, () -> "changeMethodTypeInternal must not change the descriptor's operation");
+            alwaysAssert(newMethodType == changed.methodType, () -> "changeMethodTypeInternal didn't set the correct new method type");
         }
-
         return changed;
     }
 
     /**
-     * Creates a new call site descriptor from this descriptor, which is
-     * identical to this, except it changes the method type. Subclasses must
-     * override this method to return an object of their exact class.
+     * Finds or creates a call site descriptor that only differs in its
+     * method type from this descriptor. Subclasses must override this method
+     * to return an object of their exact class. If an overridden method changes
+     * something other than the method type in the descriptor (its class, lookup,
+     * or operation), or returns null, an {@code AssertionError} will be thrown
+     * from {@link #changeMethodType(MethodType)}.
      *
      * @param newMethodType the new method type
-     * @return a new call site descriptor, with the method type changed.
+     * @return a call site descriptor with the changed method type.
      */
     protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
         return new CallSiteDescriptor(getLookupPrivileged(), operation, newMethodType);
     }
 
     /**
+     * Finds or creates a call site descriptor that only differs in its
+     * operation from this descriptor.
+     * Invokes {@link #changeOperationInternal(Operation)}.
+     *
+     * @param newOperation the new operation
+     * @return a call site descriptor with the changed operation.
+     * @throws NullPointerException if {@code newOperation} is null.
+     * @throws SecurityException if the descriptor's lookup isn't the
+     * {@link MethodHandles#publicLookup()}, and a security manager is present,
+     * and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
+     * This is necessary as changing the operation in the call site descriptor
+     * allows fabrication of descriptors for arbitrary operations with the lookup.
+     */
+    public final CallSiteDescriptor changeOperation(final Operation newOperation) {
+        getLookup(); // force security check
+        final CallSiteDescriptor changed = changeOperationInternal(newOperation);
+
+        if (getClass() != CallSiteDescriptor.class) {
+            assertChangeInvariants(changed, "changeOperationInternal");
+            alwaysAssert(methodType == changed.methodType, () -> "changeOperationInternal must not change the descriptor's method type");
+            alwaysAssert(newOperation == changed.operation, () -> "changeOperationInternal didn't set the correct new operation");
+        }
+        return changed;
+    }
+
+    /**
+     * Finds or creates a call site descriptor that only differs in its
+     * operation from this descriptor. Subclasses must override this method
+     * to return an object of their exact class. If an overridden method changes
+     * something other than the operation in the descriptor (its class, lookup,
+     * or method type), or returns null, an {@code AssertionError} will be thrown
+     * from {@link #changeOperation(Operation)}.
+     *
+     * @param newOperation the new operation
+     * @return a call site descriptor with the changed operation.
+     */
+    protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
+        return new CallSiteDescriptor(getLookupPrivileged(), newOperation, methodType);
+    }
+
+    /**
      * Returns true if this call site descriptor is equal to the passed object.
      * It is considered equal if the other object is of the exact same class,
      * their operations and method types are equal, and their lookups have the
@@ -255,4 +295,16 @@
         final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length());
         return b.append(o).append(mt).append('@').append(l).toString();
     }
+
+    private void assertChangeInvariants(final CallSiteDescriptor changed, final String caller) {
+        alwaysAssert(changed != null, () -> caller + " must not return null.");
+        alwaysAssert(getClass() == changed.getClass(), () -> caller + " must not change the descriptor's class");
+        alwaysAssert(lookupsEqual(getLookupPrivileged(), changed.getLookupPrivileged()), () -> caller + " must not change the descriptor's lookup");
+    }
+
+    private static void alwaysAssert(final boolean cond, final Supplier<String> errorMessage) {
+        if (!cond) {
+            throw new AssertionError(errorMessage.get());
+        }
+    }
 }
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java
deleted file mode 100644
index 94581f4..0000000
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file, and Oracle licenses the original version of this file under the BSD
- * license:
- */
-/*
-   Copyright 2015 Attila Szegedi
-
-   Licensed under both the Apache License, Version 2.0 (the "Apache License")
-   and the BSD License (the "BSD License"), with licensee being free to
-   choose either of the two at their discretion.
-
-   You may not use this file except in compliance with either the Apache
-   License or the BSD License.
-
-   If you choose to use this file in compliance with the Apache License, the
-   following notice applies to you:
-
-       You may obtain a copy of the Apache License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing, software
-       distributed under the License is distributed on an "AS IS" BASIS,
-       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-       implied. See the License for the specific language governing
-       permissions and limitations under the License.
-
-   If you choose to use this file in compliance with the BSD License, the
-   following notice applies to you:
-
-       Redistribution and use in source and binary forms, with or without
-       modification, are permitted provided that the following conditions are
-       met:
-       * Redistributions of source code must retain the above copyright
-         notice, this list of conditions and the following disclaimer.
-       * Redistributions in binary form must reproduce the above copyright
-         notice, this list of conditions and the following disclaimer in the
-         documentation and/or other materials provided with the distribution.
-       * Neither the name of the copyright holder nor the names of
-         contributors may be used to endorse or promote products derived from
-         this software without specific prior written permission.
-
-       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package jdk.dynalink;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * Describes an operation that is composed of at least two other operations. The
- * component operations are treated as alternatives to each other in order of
- * preference. The semantics of the composite operation is "first successful".
- * That is, a composite of {@code GET_PROPERTY|GET_ELEMENT:color} should be
- * interpreted as <i>get the property named "color" on the object, but if the
- * property does not exist, then get the collection element named "color"
- * instead</i>.
- * <p>
- * Composite operations are helpful in implementation of languages that
- * don't distinguish between one or more of the property, method, and element
- * namespaces, or when expressing operations against objects that can be
- * considered both ordinary objects and collections, e.g. Java
- * {@link java.util.Map} objects. A composite operation
- * {@code GET_PROPERTY|GET_ELEMENT:empty} against a Java map will always match
- * the {@link java.util.Map#isEmpty()} property, but
- * {@code GET_ELEMENT|GET_PROPERTY:empty} will actually match a map element with
- * key {@code "empty"} if the map contains that key, and only fall back to the
- * {@code isEmpty()} property getter if the map does not contain the key. If
- * the source language mandates this semantics, it can be easily achieved using
- * composite operations.
- * <p>
- * Even if the language itself doesn't distinguish between some of the
- * namespaces, it can be helpful to map different syntaxes to different
- * compositions. E.g. the source expression {@code obj.color} could map to
- * {@code GET_PROPERTY|GET_ELEMENT|GET_METHOD:color}, but a different source
- * expression that looks like collection element access {@code obj[key]} could
- * be expressed instead as {@code GET_ELEMENT|GET_PROPERTY|GET_METHOD}.
- * Finally, if the retrieved value is subsequently called, then it makes sense
- * to bring {@code GET_METHOD} to the front of the list: the getter part of the
- * source expression {@code obj.color()} should be
- * {@code GET_METHOD|GET_PROPERTY|GET_ELEMENT:color} and the one for
- * {@code obj[key]()} should be {@code GET_METHOD|GET_ELEMENT|GET_PROPERTY}.
- * <p>
- * The elements of a composite operation can not be composites or named
- * operations, but rather simple operations such are elements of
- * {@link StandardOperation}. A composite operation itself can serve as the base
- * operation of a named operation, though; a typical way to construct e.g. the
- * {@code GET_ELEMENT|GET_PROPERTY:empty} from above would be:
- * <pre>
- * Operation getElementOrPropertyEmpty = new NamedOperation(
- *     new CompositeOperation(
- *         StandardOperation.GET_ELEMENT,
- *         StandardOperation.GET_PROPERTY),
- *     "empty");
- * </pre>
- * <p>
- * Not all compositions make sense. Typically, any combination in any order of
- * standard getter operations {@code GET_PROPERTY}, {@code GET_ELEMENT}, and
- * {@code GET_METHOD} make sense, as do combinations of {@code SET_PROPERTY} and
- * {@code SET_ELEMENT}; other standard operations should not be combined. The
- * constructor will allow any combination of operations, though.
- */
-public final class CompositeOperation implements Operation {
-    private final Operation[] operations;
-
-    /**
-     * Constructs a new composite operation.
-     * @param operations the components for this composite operation. The passed
-     * array will be cloned.
-     * @throws IllegalArgumentException if less than two components are
-     * specified, or any component is itself a {@link CompositeOperation} or a
-     * {@link NamedOperation}.
-     * @throws NullPointerException if either the operations array or any of its
-     * elements are {@code null}.
-     */
-    public CompositeOperation(final Operation... operations) {
-        Objects.requireNonNull(operations, "operations array is null");
-        if (operations.length < 2) {
-            throw new IllegalArgumentException("Must have at least two operations");
-        }
-        final Operation[] clonedOps = operations.clone();
-        for(int i = 0; i < clonedOps.length; ++i) {
-            final Operation op = clonedOps[i];
-            if (op == null) {
-                throw new NullPointerException("operations[" + i + "] is null");
-            } else if (op instanceof NamedOperation) {
-                throw new IllegalArgumentException("operations[" + i + "] is a NamedOperation");
-            } else if (op instanceof CompositeOperation) {
-                throw new IllegalArgumentException("operations[" + i + "] is a CompositeOperation");
-            }
-        }
-        this.operations = clonedOps;
-    }
-
-    /**
-     * Returns the component operations in this composite operation. The
-     * returned array is a copy and changes to it don't have effect on this
-     * object.
-     * @return the component operations in this composite operation.
-     */
-    public Operation[] getOperations() {
-        return operations.clone();
-    }
-
-    /**
-     * Returns the number of component operations in this composite operation.
-     * @return the number of component operations in this composite operation.
-     */
-    public int getOperationCount() {
-        return operations.length;
-    }
-
-    /**
-     * Returns the i-th component operation in this composite operation.
-     * @param i the operation index
-     * @return the i-th component operation in this composite operation.
-     * @throws IndexOutOfBoundsException if the index is out of range.
-     */
-    public Operation getOperation(final int i) {
-        try {
-            return operations[i];
-        } catch (final ArrayIndexOutOfBoundsException e) {
-            throw new IndexOutOfBoundsException(Integer.toString(i));
-        }
-    }
-
-    /**
-     * Returns true if this composite operation contains an operation equal to
-     * the specified operation.
-     * @param operation the operation being searched for. Must not be null.
-     * @return true if the if this composite operation contains an operation
-     * equal to the specified operation.
-     */
-    public boolean contains(final Operation operation) {
-        Objects.requireNonNull(operation);
-        for(final Operation component: operations) {
-            if (component.equals(operation)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if the other object is also a composite operation and their
-     * component operations are equal.
-     * @param obj the object to compare to
-     * @return true if this object is equal to the other one, false otherwise.
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj instanceof CompositeOperation) {
-            return Arrays.equals(operations, ((CompositeOperation)obj).operations);
-        }
-        return false;
-    }
-
-    /**
-     * Returns the hash code of this composite operation. Defined to be equal
-     * to {@code java.util.Arrays.hashCode(operations)}.
-     */
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(operations);
-    };
-
-    /**
-     * Returns the string representation of this composite operation. Defined to
-     * be the {@code toString} of its component operations, each separated by
-     * the vertical line character (e.g. {@code "GET_PROPERTY|GET_ELEMENT"}).
-     * @return the string representation of this composite operation.
-     */
-    @Override
-    public String toString() {
-        final StringBuilder b = new StringBuilder();
-        b.append(operations[0]);
-        for(int i = 1; i < operations.length; ++i) {
-            b.append('|').append(operations[i]);
-        }
-        return b.toString();
-    }
-
-    /**
-     * Returns the components of the passed operation if it is a composite
-     * operation, otherwise returns an array containing the operation itself.
-     * This allows for returning an array of component even if it is not known
-     * whether the operation is itself a composite (treating a non-composite
-     * operation as if it were a single-element composite of itself).
-     * @param op the operation whose components are retrieved.
-     * @return if the passed operation is a composite operation, returns its
-     * {@link #getOperations()}, otherwise returns the operation itself.
-     */
-    public static Operation[] getOperations(final Operation op) {
-        return op instanceof CompositeOperation
-                ? ((CompositeOperation)op).operations.clone()
-                : new Operation[] { op };
-    }
-
-    /**
-     * Returns true if the specified potentially composite operation is a
-     * {@link CompositeOperation} and contains an operation equal to the
-     * specified operation. If {@code composite} is not a
-     * {@link CompositeOperation}, then the two operations are compared for
-     * equality.
-     * @param composite the potentially composite operation. Must not be null.
-     * @param operation the operation being searched for. Must not be null.
-     * @return true if the if the passed operation is a
-     * {@link CompositeOperation} and contains a component operation equal to
-     * the specified operation, or if it is not a {@link CompositeOperation} and
-     * is equal to {@code operation}.
-     */
-    public static boolean contains(final Operation composite, final Operation operation) {
-        if (composite instanceof CompositeOperation) {
-            return ((CompositeOperation)composite).contains(operation);
-        }
-        return composite.equals(Objects.requireNonNull(operation));
-    }
-}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
index 8eaa42f..d2b2336 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
@@ -88,15 +88,47 @@
 /**
  * Operation that associates a name with another operation. Typically used with
  * operations that normally take a name or an index to bind them to a fixed
- * name. E.g. {@code new NamedOperation(StandardOperation.GET_PROPERTY, "color")}
+ * name. E.g.
+ * <pre>
+ *     new NamedOperation(
+ *         new NamespaceOperation(
+ *             StandardOperation.GET,
+ *             StandardNamespace.PROPERTY),
+ *         "color")
+ * </pre>
  * will be a named operation for getting the property named "color" on the
  * object it is applied to, and
- * {@code new NamedOperation(StandardOperation.GET_ELEMENT, 3)} will be a named
- * operation for getting the element at index 3 from the collection it is
- * applied to. In these cases, the expected signature of the call site for the
+ * <pre>
+ *     new NamedOperation(
+ *         new NamespaceOperation(
+ *             StandardOperation.GET,
+ *             StandardNamespace.ELEMENT),
+ *         3)
+ * </pre>
+ * will be a named operation for getting the element at index 3 from the collection
+ * it is applied to ("name" in this context is akin to "address" and encompasses both
+ * textual names, numeric indices, or any other kinds of addressing that linkers can
+ * understand). In these cases, the expected signature of the call site for the
  * operation will change to no longer include the name parameter. Specifically,
  * the documentation for all {@link StandardOperation} members describes how
  * they are affected by being incorporated into a named operation.
+ * <p>While {@code NamedOperation} can be constructed directly, it is often convenient
+ * to use the {@link Operation#named(Object)} factory method instead, e.g.:
+ * <pre>
+ *    StandardOperation.GET
+ *        .withNamespace(StandardNamespace.ELEMENT),
+ *        .named(3)
+ *     )
+ * </pre>
+ * <p>
+ * Even though {@code NamedOperation} is most often used with {@link NamespaceOperation} as
+ * its base, it can have other operations as its base too (except another named operation).
+ * Specifically, {@link StandardOperation#CALL} as well as {@link StandardOperation#NEW} can
+ * both be used with {@code NamedOperation} directly. The contract for these operations is such
+ * that when they are used as named operations, their name is only used for diagnostic messages,
+ * usually containing the textual representation of the source expression that retrieved the
+ * callee, e.g. {@code StandardOperation.CALL.named("window.open")}.
+ * </p>
  */
 public final class NamedOperation implements Operation {
     private final Operation baseOperation;
@@ -116,7 +148,7 @@
      */
     public NamedOperation(final Operation baseOperation, final Object name) {
         if (baseOperation instanceof NamedOperation) {
-            throw new IllegalArgumentException("baseOperation is a named operation");
+            throw new IllegalArgumentException("baseOperation is a NamedOperation");
         }
         this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
         this.name = Objects.requireNonNull(name, "name is null");
@@ -139,6 +171,16 @@
     }
 
     /**
+     * Finds or creates a named operation that differs from this one only in the name.
+     * @param newName the new name to replace the old name with.
+     * @return a named operation with the changed name.
+     * @throws NullPointerException if the name is null.
+     */
+    public final NamedOperation changeName(final String newName) {
+        return new NamedOperation(baseOperation, newName);
+    }
+
+    /**
      * Compares this named operation to another object. Returns true if the
      * other object is also a named operation, and both their base operations
      * and name are equal.
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java
new file mode 100644
index 0000000..0785f64
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2016 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.dynalink;
+
+/**
+ * An object that describes a namespace that is the target of a dynamic operation
+ * on an object. Every object can have one or more namespaces. Dynalink defines a
+ * set of standard namespaces with the {@link StandardNamespace} enum. Operations
+ * that need to specify a namespace they operate on can be expressed using
+ * {@link NamespaceOperation}.
+ */
+public interface Namespace {
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java
new file mode 100644
index 0000000..26173c8
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2016 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.dynalink;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Describes an operation that operates on at least one {@link Namespace} of
+ * an object. E.g. a property getter would be described as
+ * <pre>
+ * Operation propertyGetter = new NamespaceOperation(
+ *     StandardOperation.GET,
+ *     StandardNamespace.PROPERTY);
+ * </pre>
+ * They are often combined with {@link NamedOperation}, e.g. to express a
+ * property getter for a property named "color", you would construct:
+ * <pre>
+ * Operation colorPropertyGetter = new NamedOperation(
+ *     new NamespaceOperation(
+ *         StandardOperation.GET,
+ *         StandardNamespace.PROPERTY),
+ *     "color");
+ * </pre>
+ * <p>While {@code NamespaceOperation} can be constructed directly, it is often convenient
+ * to use the {@link Operation#withNamespace(Namespace)} and {@link Operation#withNamespaces(Namespace...)} factory
+ * methods instead, e.g.:
+ * <pre>
+ * Operation getElementOrPropertyEmpty =
+ *     StandardOperation.GET
+ *         .withNamespace(StandardNamespace.PROPERTY)
+ *         .named("color");
+ * </pre>
+ * <h3>Operations on multiple namespaces</h3>
+ * If multiple namespaces are specified, the namespaces are treated as
+ * alternatives to each other in order of preference. The semantics of
+ * such operation is "first applicable".
+ * That is, a composite of {@code GET:PROPERTY|ELEMENT:color} should be
+ * interpreted as <i>get the property named "color" on the object, but if the
+ * property does not exist, then get the collection element named "color"
+ * instead</i>.
+ * <p>
+ * Operations with multiple namespaces are helpful in implementation of languages that
+ * don't distinguish between one or more of the namespaces, or when expressing operations
+ * against objects that can be considered both ordinary objects and collections, e.g. Java
+ * {@link java.util.Map} objects. A {@code GET:PROPERTY|ELEMENT:empty} operation
+ * against a Java map will always match
+ * the {@link java.util.Map#isEmpty()} property, but
+ * {@code GET:ELEMENT|PROPERTY:empty} will actually match a map element with
+ * key {@code "empty"} if the map contains that key, and only fall back to the
+ * {@code isEmpty()} property getter if the map does not contain the key. If
+ * the source language mandates this semantics, it can be easily achieved using
+ * operations on multiple namespaces.
+ * <p>
+ * Even if the language itself doesn't distinguish between some of the
+ * namespaces, it can be helpful to map different syntaxes to different namespace orderings.
+ * E.g. the source expression {@code obj.color} could map to
+ * {@code GET:PROPERTY|ELEMENT|METHOD:color}, but a different source
+ * expression that looks like collection element access {@code obj[key]} could
+ * be expressed instead as {@code GET:ELEMENT|PROPERTY|METHOD} in order to favor the
+ * element semantics. Finally, if the retrieved value is subsequently called, then it makes sense
+ * to bring {@code METHOD} to the front of the namespace list: the getter part of the
+ * source expression {@code obj.color()} could be
+ * {@code GET:METHOD|PROPERTY|ELEMENT:color} and the one for
+ * {@code obj[key]()} could be {@code GET:METHOD|ELEMENT|PROPERTY}.
+ * <p>
+ * The base operation of a namespace operation can not itself be a namespace or named
+ * operation, but rather one of simple operations such are elements of
+ * {@link StandardOperation}. A namespace operation itself can serve as the base
+ * operation of a named operation, though; a typical way to construct e.g. the
+ * {@code GET:ELEMENT|PROPERTY:empty} from above would be:
+ * <pre>
+ * Operation getElementOrPropertyEmpty = StandardOperation.GET
+ *     .withNamespaces(
+ *         StandardNamespace.ELEMENT,
+ *         StandardNamespace.PROPERTY)
+ *     .named("empty");
+ * </pre>
+ */
+public final class NamespaceOperation implements Operation {
+    private final Operation baseOperation;
+    private final Namespace[] namespaces;
+
+    /**
+     * Constructs a new namespace operation.
+     * @param baseOperation the base operation that operates on one or more namespaces.
+     * @param namespaces one or more namespaces this operation operates on.
+     * @throws IllegalArgumentException if less than one namespace is
+     * specified, or the base operation is itself a {@link NamespaceOperation} or a
+     * {@link NamedOperation}.
+     * @throws NullPointerException if either the {@code namespaces} array or any of its
+     * elements are {@code null}, or if {@code baseOperation} is {@code null}.
+     */
+    public NamespaceOperation(final Operation baseOperation, final Namespace... namespaces) {
+        this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
+        if (baseOperation instanceof NamedOperation) {
+            throw new IllegalArgumentException("baseOperation is a NamedOperation");
+        } else if (baseOperation instanceof NamespaceOperation) {
+           throw new IllegalArgumentException("baseOperation is a NamespaceOperation");
+        }
+
+        this.namespaces = Objects.requireNonNull(namespaces, "namespaces array is null").clone();
+        if (namespaces.length < 1) {
+            throw new IllegalArgumentException("Must specify at least one namespace");
+        }
+        for(int i = 0; i < namespaces.length; ++i) {
+            final int fi = i;
+            Objects.requireNonNull(namespaces[i], () -> "operations[" + fi + "] is null");
+        }
+    }
+
+    /**
+     * Returns the base operation of this named operation.
+     * @return the base operation of this named operation.
+     */
+    public Operation getBaseOperation() {
+        return baseOperation;
+    }
+
+    /**
+     * Returns the namespaces in this namespace operation. The returned
+     * array is a copy and changes to it don't have effect on this
+     * object.
+     * @return the namespaces in this namespace operation.
+     */
+    public Namespace[] getNamespaces() {
+        return namespaces.clone();
+    }
+
+    /**
+     * Returns the number of namespaces in this namespace operation.
+     * @return the number of namespaces in this namespace operation.
+     */
+    public int getNamespaceCount() {
+        return namespaces.length;
+    }
+
+    /**
+     * Returns the i-th namespace in this namespace operation.
+     * @param i the namespace index
+     * @return the i-th namespace in this namespace operation.
+     * @throws IndexOutOfBoundsException if the index is out of range.
+     */
+    public Namespace getNamespace(final int i) {
+        try {
+            return namespaces[i];
+        } catch (final ArrayIndexOutOfBoundsException e) {
+            throw new IndexOutOfBoundsException(Integer.toString(i));
+        }
+    }
+
+    /**
+     * Returns true if this namespace operation contains a namespace equal to
+     * the specified namespace.
+     * @param namespace the namespace being searched for. Must not be null.
+     * @return true if the if this namespace operation contains a namespace
+     * equal to the specified namespace.
+     */
+    public boolean contains(final Namespace namespace) {
+        Objects.requireNonNull(namespace);
+        for(final Namespace component: namespaces) {
+            if (component.equals(namespace)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the other object is also a namespace operation and their
+     * base operation and namespaces are equal.
+     * @param obj the object to compare to
+     * @return true if this object is equal to the other one, false otherwise.
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj instanceof NamespaceOperation) {
+            final NamespaceOperation other = (NamespaceOperation)obj;
+            return baseOperation.equals(other.baseOperation) && Arrays.equals(namespaces, other.namespaces);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the hash code of this namespace operation. Defined to be equal
+     * to {@code baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces)}.
+     */
+    @Override
+    public int hashCode() {
+        return baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces);
+    };
+
+    /**
+     * Returns the string representation of this namespace operation. Defined to
+     * be the {@code toString} of its base operation, followed by a colon character,
+     * followed with the list of its namespaces separated with the vertical line
+     * character (e.g. {@code "GET:PROPERTY|ELEMENT"}).
+     * @return the string representation of this namespace operation.
+     */
+    @Override
+    public String toString() {
+        final StringBuilder b = new StringBuilder();
+        b.append(baseOperation).append(':');
+        b.append(namespaces[0]);
+        for(int i = 1; i < namespaces.length; ++i) {
+            b.append('|').append(namespaces[i]);
+        }
+        return b.toString();
+    }
+
+    /**
+     * If the passed operation is a namespace operation, returns its
+     * {@link #getBaseOperation()}, otherwise returns the operation as is.
+     * @param op the operation
+     * @return the base operation of the passed operation.
+     */
+    public static Operation getBaseOperation(final Operation op) {
+        return op instanceof NamespaceOperation ? ((NamespaceOperation )op).getBaseOperation() : op;
+    }
+
+    /**
+     * If the passed operation is a namespace operation, returns its
+     * {@link #getNamespaces()}, otherwise returns an empty array.
+     * @param op the operation
+     * @return the namespaces of the passed operation.
+     */
+    public static Namespace[] getNamespaces(final Operation op) {
+        return op instanceof NamespaceOperation ? ((NamespaceOperation)op).getNamespaces() : new Namespace[0];
+    }
+
+    /**
+     * Returns true if the specified operation is a {@link NamespaceOperation}
+     * and its base operation is equal to the specified operation, and it
+     * contains the specified namespace. If it is not a {@link NamespaceOperation},
+     * then it returns false.
+     * @param op the operation. Must not be null.
+     * @param baseOperation the base operation being searched for. Must not be null.
+     * @param namespace the namespace being searched for. Must not be null.
+     * @return true if the if the passed operation is a {@link NamespaceOperation},
+     * its base operation equals the searched base operation, and contains a namespace
+     * equal to the searched namespace.
+     */
+    public static boolean contains(final Operation op, final Operation baseOperation, final Namespace namespace) {
+        if (op instanceof NamespaceOperation) {
+            final NamespaceOperation no = (NamespaceOperation)op;
+            return no.baseOperation.equals(baseOperation) && no.contains(namespace);
+        }
+        return false;
+    }
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
index 1afdd6e..e73e88f 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
@@ -86,14 +86,51 @@
 /**
  * An object that describes a dynamic operation. Dynalink defines a set of
  * standard operations with the {@link StandardOperation} class, as well as a
- * way to attach a fixed name to an operation using {@link NamedOperation} and
- * to express a set of alternative operations using {@link CompositeOperation}.
+ * way to express the target {@link Namespace namespace(s)} of an operation
+ * on an object using {@link NamespaceOperation} and finally a way to attach
+ * a fixed target name to an operation using {@link NamedOperation}.
  * When presenting examples in this documentation, we will refer to standard
- * operations using their name (e.g. {@code GET_PROPERTY}), to composite
- * operations by separating their components with the vertical line character
- * (e.g. {@code GET_PROPERTY|GET_ELEMENT}), and finally to named operations by
- * separating the base operation and the name with the colon character (e.g.
- * {@code GET_PROPERTY|GET_ELEMENT:color}).
+ * operations using their name (e.g. {@code GET}), to namespace operations
+ * by separating their base operation with a colon from their namespace
+ * (e.g. {@code GET:PROPERTY}), or in case of multiple namespaces we will
+ * further separate those with the vertical line character (e.g.
+ * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations
+ * by separating the base operation and the name with the colon character (e.g.
+ * {@code GET:PROPERTY|ELEMENT:color}).
  */
 public interface Operation {
+    /**
+     * Returns a {@link NamespaceOperation} using this operation as its base.
+     * @param namespace the namespace that is the target of the namespace operation.
+     * @return a {@link NamespaceOperation} with this operation as its base and the specified
+     * namespace as its target.
+     * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation.
+     * @throws NullPointerException if {@code namespace} is null.
+     */
+    default NamespaceOperation withNamespace(final Namespace namespace) {
+        return withNamespaces(namespace);
+    }
+
+    /**
+     * Returns a {@link NamespaceOperation} using this operation as its base.
+     * @param namespaces the namespaces that are the target of the namespace operation.
+     * @return a {@link NamespaceOperation} with this operation as its base and the specified
+     * namespaces as its targets.
+     * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation.
+     * @throws NullPointerException if {@code namespace} or any of its elements is null.
+     */
+    default NamespaceOperation withNamespaces(final Namespace... namespaces) {
+        return new NamespaceOperation(this, namespaces);
+    }
+
+    /**
+     * Returns a {@link NamedOperation} using this operation as its base.
+     * @param name the name that is the target of the named operation.
+     * @return a {@link NamedOperation} with this operation as its base and the specified name.
+     * @throws IllegalArgumentException if this operation is already a named operation.
+     * @throws NullPointerException if {@code name} is null.
+     */
+    default NamedOperation named(final Object name) {
+        return new NamedOperation(this, name);
+    }
 }
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java
new file mode 100644
index 0000000..af0b25b
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2016 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.dynalink;
+
+/**
+ * An enumeration of standard namespaces defined by Dynalink.
+ */
+public enum StandardNamespace implements Namespace {
+    /**
+     * Standard namespace for properties of an object.
+     */
+    PROPERTY,
+    /**
+     * Standard namespace for elements of a collection object.
+     */
+    ELEMENT,
+    /**
+     * Standard namespace for methods of an object. The method objects retrieved
+     * through a {@link StandardOperation#GET} on this namespace can be (and where
+     * object semantics allows they should be) unbound, that is: not bound to the
+     * object they were retrieved through. When they are used with
+     * {@link StandardOperation#CALL} an explicit "this" receiver argument is always
+     * passed to them. Of course bound methods can be returned if the object semantics
+     * requires them and such methods are free to ignore the receiver passed in the
+     * {@code CALL} operation or even raise an error when it is different from the one
+     * the method is bound to, or exhibit any other behavior their semantics requires
+     * in such case.
+     */
+    METHOD;
+
+    /**
+     * If the passed in operation is a {@link NamespaceOperation}, or a
+     * {@link NamedOperation} wrapping a {@link NamespaceOperation}, then it
+     * returns the first (if any) {@link StandardNamespace} in its namespace
+     * list. If the passed operation is not a namespace operation (optionally
+     * wrapped in a named operation), or if it doesn't have any standard
+     * namespaces in it, returns {@code null}.
+     * @param op the operation
+     * @return the first standard namespace in the operation's namespace list
+     */
+    public static StandardNamespace findFirst(final Operation op) {
+        for(final Namespace ns: NamespaceOperation.getNamespaces(NamedOperation.getBaseOperation(op))) {
+            if (ns instanceof StandardNamespace) {
+                return (StandardNamespace)ns;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
index 7fbc943..e5acb1b 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
@@ -84,79 +84,40 @@
 package jdk.dynalink;
 
 /**
- * Defines the standard dynamic operations. Getter and setter operations defined
- * in this enumeration can be composed into a {@link CompositeOperation}, and
- * {@link NamedOperation} can be used to bind the name parameter of operations
- * that take one, in which case it disappears from the type signature.
+ * Defines the standard dynamic operations. The operations {@link #GET} and {@link #SET} must
+ * be used as part of a {@link NamespaceOperation}. {@link NamedOperation} can then be further used on these
+ * {@link NamespaceOperation}s to bind the name parameter of {@link #GET} and {@link #SET} operations, in which case it
+ * disappears from their type signature.
+ * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a
+ * diagnostic name, and as such it does not affect their type signature.
  */
 public enum StandardOperation implements Operation {
     /**
-     * Get the value of a property defined on an object. Call sites with this
+     * Get the value from a namespace defined on an object. Call sites with this
      * operation should have a signature of
-     * <tt>(receiver,&nbsp;propertyName)&rarr;value</tt> or
+     * <tt>(receiver,&nbsp;name)&rarr;value</tt> or
      * <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}, with
      * all parameters and return type being of any type (either primitive or
-     * reference).
+     * reference). This operation must always be used as part of a {@link NamespaceOperation}.
      */
-    GET_PROPERTY,
+    GET,
     /**
-     * Set the value of a property defined on an object. Call sites with this
+     * Set the value in a namespace defined on an object. Call sites with this
      * operation should have a signature of
-     * <tt>(receiver,&nbsp;propertyName,&nbsp;value)&rarr;void</tt> or
+     * <tt>(receiver,&nbsp;name,&nbsp;value)&rarr;void</tt> or
      * <tt>(receiver,&nbsp;value)&rarr;void</tt> when used with {@link NamedOperation},
      * with all parameters and return type being of any type (either primitive
-     * or reference).
+     * or reference). This operation must always be used as part of a {@link NamespaceOperation}.
      */
-    SET_PROPERTY,
+    SET,
     /**
-     * Get the value of an element of a collection. Call sites with this
-     * operation should have a signature of
-     * <tt>(receiver,&nbsp;index)&rarr;value</tt> or
-     * <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}, with
-     * all parameters and return type being of any type (either primitive or
-     * reference).
-     */
-    GET_ELEMENT,
-    /**
-     * Set the value of an element of a collection. Call sites with this
-     * operation should have a signature of
-     * <tt>(receiver,&nbsp;index,&nbsp;value)&rarr;void</tt> or
-     * <tt>(receiver,&nbsp;value)&rarr;void</tt> when used with {@link NamedOperation},
-     * with all parameters and return type being of any type (either primitive
-     * or reference).
-     */
-    SET_ELEMENT,
-    /**
-     * Get the length of an array or size of a collection. Call sites with
-     * this operation should have a signature of <tt>(receiver)&rarr;value</tt>,
-     * with all parameters and return type being of any type (either primitive
-     * or reference).
-     */
-    GET_LENGTH,
-    /**
-     * Gets an object representing a method defined on an object. Call sites
-     * with this operation should have a signature of
-     * <tt>(receiver,&nbsp;methodName)&rarr;value</tt>, or
-     * <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}
-     * with all parameters and return type being of any type (either primitive
-     * or reference).
-     */
-    GET_METHOD,
-    /**
-     * Calls a method defined on an object. Call sites with this
-     * operation should have a signature of
-     * <tt>(receiver,&nbsp;methodName,&nbsp;arguments...)&rarr;value</tt> or
-     * <tt>(receiver,&nbsp;arguments...)&rarr;value</tt> when used with {@link NamedOperation},
-     * with all parameters and return type being of any type (either primitive
-     * or reference).
-     */
-    CALL_METHOD,
-    /**
-     * Calls a callable object. Call sites with this operation should have a
-     * signature of <tt>(receiver,&nbsp;arguments...)&rarr;value</tt>, with all
-     * parameters and return type being of any type (either primitive or
-     * reference). Typically, if the callable is a method of an object, the
-     * first argument will act as the "this" value passed to the called method.
+     * Call a callable object. Call sites with this operation should have a
+     * signature of <tt>(callable,&nbsp;receiver,&nbsp;arguments...)&rarr;value</tt>,
+     * with all parameters and return type being of any type (either primitive or
+     * reference). Typically, the callables are presumed to be methods of an object, so
+     * an explicit receiver value is always passed to the callable before the arguments.
+     * If a callable has no concept of a receiver, it is free to ignore the value of the
+     * receiver argument.
      * The <tt>CALL</tt> operation is allowed to be used with a
      * {@link NamedOperation} even though it does not take a name. Using it with
      * a named operation won't affect its signature; the name is solely meant to
@@ -164,8 +125,8 @@
      */
     CALL,
     /**
-     * Calls a constructor object. Call sites with this operation should have a
-     * signature of <tt>(receiver,&nbsp;arguments...)&rarr;value</tt>, with all
+     * Call a constructor object. Call sites with this operation should have a
+     * signature of <tt>(constructor,&nbsp;arguments...)&rarr;value</tt>, with all
      * parameters and return type being of any type (either primitive or
      * reference). The <tt>NEW</tt> operation is allowed to be used with a
      * {@link NamedOperation} even though it does not take a name. Using it with
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
index 75c5065..f648a81 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
@@ -99,9 +99,11 @@
 import java.util.Map;
 import java.util.Set;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Namespace;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
 import jdk.dynalink.internal.InternalTypeUtilities;
@@ -360,22 +362,6 @@
             directLinkerServices = linkerServices;
         }
 
-        // Handle NamedOperation(CALL_METHOD, name) separately
-        final Operation operation = callSiteDescriptor.getOperation();
-        if (operation instanceof NamedOperation) {
-            final NamedOperation namedOperation = (NamedOperation)operation;
-            if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) {
-                final GuardedInvocation inv =
-                        createGuardedDynamicMethodInvocation(callSiteDescriptor,
-                        directLinkerServices, namedOperation.getName().toString(), methods);
-                if (inv == null) {
-                    return createNoSuchMemberHandler(missingMemberHandlerFactory,
-                            request, directLinkerServices).getGuardedInvocation();
-                }
-                return inv;
-            }
-        }
-
         final GuardedInvocationComponent gic = getGuardedInvocationComponent(
                 new ComponentLinkRequest(request, directLinkerServices,
                         missingMemberHandlerFactory));
@@ -386,7 +372,8 @@
         final LinkRequest linkRequest;
         final LinkerServices linkerServices;
         final MissingMemberHandlerFactory missingMemberHandlerFactory;
-        final List<Operation> operations;
+        final Operation baseOperation;
+        final List<Namespace> namespaces;
         final Object name;
 
         ComponentLinkRequest(final LinkRequest linkRequest,
@@ -395,21 +382,22 @@
             this.linkRequest = linkRequest;
             this.linkerServices = linkerServices;
             this.missingMemberHandlerFactory = missingMemberHandlerFactory;
-            final Operation operation = linkRequest.getCallSiteDescriptor().getOperation();
-            this.operations = Arrays.asList(
-                    CompositeOperation.getOperations(
-                            NamedOperation.getBaseOperation(operation)));
-            this.name = NamedOperation.getName(operation);
+            final Operation namedOp = linkRequest.getCallSiteDescriptor().getOperation();
+            this.name = NamedOperation.getName(namedOp);
+            final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+            this.baseOperation = NamespaceOperation.getBaseOperation(namespaceOp);
+            this.namespaces = Arrays.asList(NamespaceOperation.getNamespaces(namespaceOp));
         }
 
         private ComponentLinkRequest(final LinkRequest linkRequest,
                 final LinkerServices linkerServices,
                 final MissingMemberHandlerFactory missingMemberHandlerFactory,
-                final List<Operation> operations, final Object name) {
+                final Operation baseOperation, final List<Namespace> namespaces, final Object name) {
             this.linkRequest = linkRequest;
             this.linkerServices = linkerServices;
             this.missingMemberHandlerFactory = missingMemberHandlerFactory;
-            this.operations = operations;
+            this.baseOperation = baseOperation;
+            this.namespaces = namespaces;
             this.name = name;
         }
 
@@ -417,29 +405,33 @@
             return linkRequest.getCallSiteDescriptor();
         }
 
-        ComponentLinkRequest popOperations() {
+        ComponentLinkRequest popNamespace() {
             return new ComponentLinkRequest(linkRequest, linkerServices,
-                    missingMemberHandlerFactory,
-                    operations.subList(1, operations.size()), name);
+                    missingMemberHandlerFactory, baseOperation,
+                namespaces.subList(1, namespaces.size()), name);
         }
     }
 
     protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req)
     throws Exception {
-        final Operation op = req.operations.get(0);
-        if (op instanceof StandardOperation) {
-            switch((StandardOperation)op) {
-            case GET_PROPERTY: return getPropertyGetter(req.popOperations());
-            case SET_PROPERTY: return getPropertySetter(req.popOperations());
-            case GET_METHOD: return getMethodGetter(req.popOperations());
-            default:
+        if (!req.namespaces.isEmpty()) {
+            final Namespace ns = req.namespaces.get(0);
+            final Operation op = req.baseOperation;
+            if (op == StandardOperation.GET) {
+                if (ns == StandardNamespace.PROPERTY) {
+                    return getPropertyGetter(req.popNamespace());
+                } else if (ns == StandardNamespace.METHOD) {
+                    return getMethodGetter(req.popNamespace());
+                }
+            } else if (op == StandardOperation.SET && ns == StandardNamespace.PROPERTY) {
+                return getPropertySetter(req.popNamespace());
             }
         }
         return null;
     }
 
     GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception {
-        if (req.operations.isEmpty()) {
+        if (req.namespaces.isEmpty()) {
             return createNoSuchMemberHandler(req.missingMemberHandlerFactory,
                     req.linkRequest, req.linkerServices);
         }
@@ -447,7 +439,7 @@
         if (gic != null) {
             return gic;
         }
-        return getNextComponent(req.popOperations());
+        return getNextComponent(req.popNamespace());
     }
 
     private GuardedInvocationComponent createNoSuchMemberHandler(
@@ -626,8 +618,7 @@
         if(gi != null) {
             return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
         }
-        // If we don't have a property setter with this name, always fall back to the next operation in the
-        // composite (if any)
+        // If we don't have a property setter with this name, always fall back to the next namespace (if any).
         return getNextComponent(req);
     }
 
@@ -808,8 +799,8 @@
             // We have no such method, always delegate to the next component
             return getNextComponent(req);
         }
-        // No delegation to the next component of the composite operation; if we have a method with that name,
-        // we'll always return it at this point.
+        // No delegation to the next namespace; if we have a method with that name, we'll always return it at
+        // this point.
         final MethodType type = getMethodGetterType(req);
         return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments(
                 MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
@@ -880,7 +871,7 @@
     @SuppressWarnings("unused")
     // This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
     // want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
-    // GET_METHOD linking).
+    // GET:METHOD linking).
     private Object getDynamicMethod(final Object name) {
         return getDynamicMethod(String.valueOf(name), methods);
     }
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
index 3f98c2b..d865ec5 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
@@ -92,7 +92,9 @@
 import java.util.List;
 import java.util.Map;
 import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.Namespace;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
 import jdk.dynalink.linker.GuardedInvocation;
@@ -112,10 +114,11 @@
         if(clazz.isArray()) {
             // Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
             // explicit property is beneficial for them.
-            // REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed?
             setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
-        } else if(List.class.isAssignableFrom(clazz)) {
+        } else if(Collection.class.isAssignableFrom(clazz)) {
             setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
+        } else if(Map.class.isAssignableFrom(clazz)) {
+            setPropertyGetter("length", GET_MAP_LENGTH, ValidationType.INSTANCE_OF);
         }
     }
 
@@ -135,14 +138,14 @@
         if(superGic != null) {
             return superGic;
         }
-        if (!req.operations.isEmpty()) {
-            final Operation op = req.operations.get(0);
-            if (op instanceof StandardOperation) {
-                switch ((StandardOperation)op) {
-                case GET_ELEMENT: return getElementGetter(req.popOperations());
-                case SET_ELEMENT: return getElementSetter(req.popOperations());
-                case GET_LENGTH:  return getLengthGetter(req.getDescriptor());
-                default:
+        if (!req.namespaces.isEmpty()) {
+            final Operation op = req.baseOperation;
+            final Namespace ns = req.namespaces.get(0);
+            if (ns == StandardNamespace.ELEMENT) {
+                if (op == StandardOperation.GET) {
+                    return getElementGetter(req.popNamespace());
+                } else if (op == StandardOperation.SET) {
+                    return getElementSetter(req.popNamespace());
                 }
             }
         }
@@ -524,38 +527,6 @@
     private static final MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size",
             MethodType.methodType(int.class));
 
-    private static final MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class);
-
-    private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) {
-        assertParameterCount(callSiteDescriptor, 1);
-        final MethodType callSiteType = callSiteDescriptor.getMethodType();
-        final Class<?> declaredType = callSiteType.parameterType(0);
-        // If declared type of receiver at the call site is already an array, collection, or map, bind without guard.
-        // Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance
-        // they're dealing with an array, collection, or map, but hey...
-        if(declaredType.isArray()) {
-            return new GuardedInvocationComponent(MethodHandles.arrayLength(declaredType).asType(callSiteType));
-        } else if(Collection.class.isAssignableFrom(declaredType)) {
-            return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType));
-        } else if(Map.class.isAssignableFrom(declaredType)) {
-            return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType));
-        }
-
-        // Otherwise, create a binding based on the actual type of the argument with an appropriate guard.
-        if(clazz.isArray()) {
-            return new GuardedInvocationComponent(MethodHandles.arrayLength(clazz).asType(callSiteType),
-                    Guards.isArray(0, callSiteType), ValidationType.EXACT_CLASS);
-        } if(Collection.class.isAssignableFrom(clazz)) {
-            return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType(
-                    COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF);
-        } if(Map.class.isAssignableFrom(clazz)) {
-            return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD,
-                    callSiteType), Map.class, ValidationType.INSTANCE_OF);
-        }
-        // Can't retrieve length for objects that are neither arrays, nor collections, nor maps.
-        return null;
-    }
-
     private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
         if(descriptor.getMethodType().parameterCount() != paramCount) {
             throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
index 4ea49f2..5ba5626 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
@@ -87,6 +87,7 @@
 import java.util.Collections;
 import java.util.Set;
 import jdk.dynalink.DynamicLinkerFactory;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -102,21 +103,18 @@
  * <ul>
  * <li>expose all public methods of form {@code setXxx()}, {@code getXxx()},
  * and {@code isXxx()} as property setters and getters for
- * {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY}
- * operations;</li>
- * <li>expose all public methods for invocation through
- * {@link StandardOperation#CALL_METHOD} operation;</li>
+ * {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the
+ * {@link StandardNamespace#PROPERTY} namespace;</li>
  * <li>expose all public methods for retrieval for
- * {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved
- * can then be invoked using {@link StandardOperation#CALL}.</li>
+ * {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace;
+ * the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}.</li>
  * <li>expose all public fields as properties, unless there are getters or
  * setters for the properties of the same name;</li>
- * <li>expose {@link StandardOperation#GET_LENGTH},
- * {@link StandardOperation#GET_ELEMENT} and {@link StandardOperation#SET_ELEMENT}
- * on native Java arrays, as well as {@link java.util.List} and
- * {@link java.util.Map} objects; ({@link StandardOperation#GET_LENGTH} works on
- * any {@link java.util.Collection});</li>
- * <li>expose a virtual property named {@code length} on Java arrays;</li>
+ * <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as
+ * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the
+ * {@link StandardNamespace#ELEMENT} namespace;</li>
+ * <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and
+ * {@link java.util.Map} objects;</li>
  * <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
  * as calls to constructors, including those static class objects that represent
  * Java arrays (their constructors take a single {@code int} parameter
@@ -130,10 +128,10 @@
  * <p><strong>Overloaded method resolution</strong> is performed automatically
  * for property setters, methods, and constructors. Additionally, manual
  * overloaded method selection is supported by having a call site specify a name
- * for a method that contains an explicit signature, i.e.
- * {@code NamedMethod(GET_METHOD, "parseInt(String,int)")}. You can use
- * non-qualified class names in such signatures regardless of those classes'
- * packages, they will match any class with the same non-qualified name. You
+ * for a method that contains an explicit signature, e.g.
+ * {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")}
+ * You can use non-qualified class names in such signatures regardless of those
+ * classes' packages, they will match any class with the same non-qualified name. You
  * only have to use a fully qualified class name in case non-qualified class
  * names would cause selection ambiguity (that is extremely rare). Overloaded
  * resolution for constructors is not automatic as there is no logical place to
@@ -235,7 +233,7 @@
 
     /**
      * Returns true if the object is a Java dynamic method (e.g., one
-     * obtained through a {@code GET_METHOD} operation on a Java object or
+     * obtained through a {@code GET:METHOD} operation on a Java object or
      * {@link StaticClass} or through
      * {@link #getConstructorMethod(Class, String)}.
      *
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
index 9f1cf1c..3e79926 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
@@ -88,6 +88,7 @@
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
@@ -98,7 +99,8 @@
 /**
  * Simple linker that implements the {@link StandardOperation#CALL} operation
  * for {@link DynamicMethod} objects - the objects returned by
- * {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}.
+ * {@link StandardOperation#GET} on {@link StandardNamespace#METHOD} namespace through
+ * {@link AbstractJavaLinker}.
  */
 class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
     @Override
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
index 8a3e48a..0e3f832 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
@@ -87,7 +87,7 @@
 import jdk.dynalink.linker.GuardedInvocation;
 
 /**
- * Represents one component for a GuardedInvocation of a potentially composite operation of an
+ * Represents one component for a GuardedInvocation of a potentially multi-namespace operation of an
  * {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its
  * guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz"
  * expressions. This allows choosing the most restrictive guard as the guard for the composition of two components.
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
index 432b18a..748885a 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
@@ -92,7 +92,7 @@
  * methods, properties, and fields), as well as construction of instances using
  * {@link StandardOperation#NEW} operation. In Dynalink, {@link Class} objects
  * are not treated specially and act as ordinary Java objects; you can use e.g.
- * {@code NamedOperation(GET_PROPERTY, "superclass")} as a property getter to
+ * {@code GET:PROPERTY:superclass} as a property getter to
  * invoke {@code clazz.getSuperclass()}. On the other hand, you can not use
  * {@code Class} objects to access static members of a class, nor to create new
  * instances of the class using {@code NEW}. This is consistent with how
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
index c81e8d1..94d8eb8 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
@@ -91,7 +91,7 @@
 import java.util.Set;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
-import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
 import jdk.dynalink.linker.GuardedInvocation;
@@ -168,17 +168,12 @@
             if (superGic != null) {
                 return superGic;
             }
-            if (!req.operations.isEmpty()) {
-                final Operation op = req.operations.get(0);
-                if (op instanceof StandardOperation) {
-                    switch ((StandardOperation)op) {
-                    case GET_ELEMENT:
-                    case SET_ELEMENT:
-                        // StaticClass doesn't behave as a collection
-                        return getNextComponent(req.popOperations());
-                    default:
-                    }
-                }
+            if (!req.namespaces.isEmpty()
+                && req.namespaces.get(0) == StandardNamespace.ELEMENT
+                && (req.baseOperation == StandardOperation.GET || req.baseOperation == StandardOperation.SET))
+            {
+                // StaticClass doesn't behave as a collection
+                return getNextComponent(req.popNamespace());
             }
             return null;
         }
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
index e68bf14..b89f4c2 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
@@ -129,7 +129,7 @@
  * bytecode would look something like this:
  * <pre>
  * aload 2 // load "obj" on stack
- * invokedynamic "GET_PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
+ * invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
  * astore 3 // store the return value into local variable "color"
  * </pre>
  * In order to link the {@code invokedynamic} instruction, we need a bootstrap
@@ -175,9 +175,9 @@
  * dynamic operations. It does not prescribe how would you encode the operations
  * in your call site, though. That is why in the above example the
  * {@code parseOperation} function is left empty, and you would be expected to
- * provide the code to parse the string {@code "GET_PROPERTY:color"}
+ * provide the code to parse the string {@code "GET:PROPERTY:color"}
  * in the call site's name into a named property getter operation object as
- * {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}.
+ * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}.
  * </ul>
  * <p>What can you already do with the above setup? {@code DynamicLinkerFactory}
  * by default creates a {@code DynamicLinker} that can link Java objects with the
@@ -231,18 +231,20 @@
  * Dynalink defines several standard operations in its
  * {@link jdk.dynalink.StandardOperation} class. The linker for Java
  * objects can link all of these operations, and you are encouraged to at
- * minimum support and use these operations in your language too. To associate
- * a fixed name with an operation, you can use
- * {@link jdk.dynalink.NamedOperation} as in the above example where
- * {@code StandardOperation.GET_PROPERTY} was combined with the name
- * {@code "color"} in a {@code NamedOperation} to form a property getter for the
- * property named "color".
- * <h2>Composite operations</h2>
+ * minimum support and use these operations in your language too. The
+ * standard operations {@code GET} and {@code SET} need to be combined with
+ * at least one {@link jdk.dynalink.Namespace} to be useful, e.g. to express a
+ * property getter, you'd use {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)}.
+ * Dynalink defines three standard namespaces in the {@link jdk.dynalink.StandardNamespace} class.
+ * To associate a fixed name with an operation, you can use
+ * {@link jdk.dynalink.NamedOperation} as in the previous example:
+ * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}
+ * expresses a getter for the property named "color".
+ * <h2>Operations on multiple namespaces</h2>
  * Some languages might not have separate namespaces on objects for
  * properties, elements, and methods, and a source language construct might
- * address two or three of them. Dynalink supports specifying composite
- * operations for this purpose using the
- * {@link jdk.dynalink.CompositeOperation} class.
+ * address several of them at once. Dynalink supports specifying multiple
+ * {@link jdk.dynalink.Namespace} objects with {@link jdk.dynalink.NamespaceOperation}.
  * <h2>Language-specific linkers</h2>
  * Languages that define their own object model different than the JVM
  * class-based model and/or use their own type conversions will need to create
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
index 974f56c..041ab61 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
@@ -384,7 +384,7 @@
         final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size());
         for (final CatchNode catchNode : catchNodes) {
             catchTrees.add(new CatchTreeImpl(catchNode,
-                    translateIdent(catchNode.getException()),
+                    translateExpr(catchNode.getException()),
                     (BlockTree) translateBlock(catchNode.getBody()),
                     translateExpr(catchNode.getExceptionCondition())));
         }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
index e0785e6..3bb44b5 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -343,7 +343,7 @@
                     symbol = null;
                 } else if (symbol.isParam()) {
                     // Duplicate parameter. Null return will force an error.
-                    throw new AssertionError("duplicate parameter");
+                    throwParserException(ECMAErrors.getMessage("syntax.error.duplicate.parameter", name), origin);
                 }
             } else if (isVar) {
                 if (isBlockScope) {
@@ -462,7 +462,7 @@
 
     @Override
     public boolean enterCatchNode(final CatchNode catchNode) {
-        final IdentNode exception = catchNode.getException();
+        final IdentNode exception = catchNode.getExceptionIdentifier();
         final Block     block     = lc.getCurrentBlock();
 
         start(catchNode);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
index f04f895..c4053bc 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -3255,7 +3255,7 @@
             enterBlock(catchBlock);
 
             final CatchNode  catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
-            final IdentNode  exception          = catchNode.getException();
+            final IdentNode  exception          = catchNode.getExceptionIdentifier();
             final Expression exceptionCondition = catchNode.getExceptionCondition();
             final Block      catchBody          = catchNode.getBody();
 
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index cf92047..f484440 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
@@ -122,9 +123,9 @@
         private final List<JumpOrigin> origins = new LinkedList<>();
         private Map<Symbol, LvarType> types = Collections.emptyMap();
 
-        void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
+        void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) {
             origins.add(new JumpOrigin(originNode, originTypes));
-            this.types = getUnionTypes(this.types, originTypes);
+            this.types = calc.getUnionTypes(this.types, originTypes);
         }
     }
     private enum LvarType {
@@ -185,12 +186,15 @@
     }
 
     @SuppressWarnings("unchecked")
-    private static IdentityHashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
-        return (IdentityHashMap<Symbol, LvarType>)((IdentityHashMap<?,?>)map).clone();
+    private static HashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
+        return (HashMap<Symbol, LvarType>)((HashMap<?,?>)map).clone();
     }
 
     private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType,
             final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) {
+        if (invalidatedSymbols.contains(symbol)) {
+            return next;
+        }
         final LvarType targetType = joinLvarTypes.get(symbol);
         assert targetType != null;
         if(targetType == branchLvarType) {
@@ -208,7 +212,7 @@
         return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
     }
 
-    private static Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
+    private Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
         if(types1 == types2 || types1.isEmpty()) {
             return types2;
         } else if(types2.isEmpty()) {
@@ -261,6 +265,11 @@
             final LvarType type2 = types2.get(symbol);
             union.put(symbol, widestLvarType(type1,  type2));
         }
+        // If the two sets of symbols differ, there's a good chance that some of
+        // symbols only appearing in one of the sets are lexically invalidated,
+        // so we remove them from further consideration.
+        // This is not strictly necessary, just a working set size optimization.
+        union.keySet().removeAll(invalidatedSymbols);
         return union;
     }
 
@@ -359,8 +368,6 @@
         if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
             return LvarType.OBJECT;
         }
-        // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
-        // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
         return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
     }
     private final Compiler compiler;
@@ -368,7 +375,10 @@
     // Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
     // allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
     // value.
-    private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+    private Map<Symbol, LvarType> localVariableTypes = Collections.emptyMap();
+    // Set of symbols whose lexical scope has already ended.
+    private final Set<Symbol> invalidatedSymbols = new HashSet<>();
+
     // Stack for evaluated expression types.
     private final Deque<LvarType> typeStack = new ArrayDeque<>();
 
@@ -464,9 +474,19 @@
 
     @Override
     public boolean enterBlock(final Block block) {
+        boolean cloned = false;
         for(final Symbol symbol: block.getSymbols()) {
-            if(symbol.isBytecodeLocal() && getLocalVariableTypeOrNull(symbol) == null) {
-                setType(symbol, LvarType.UNDEFINED);
+            if(symbol.isBytecodeLocal()) {
+                if (getLocalVariableTypeOrNull(symbol) == null) {
+                    if (!cloned) {
+                        cloneOrNewLocalVariableTypes();
+                        cloned = true;
+                    }
+                    localVariableTypes.put(symbol, LvarType.UNDEFINED);
+                }
+                // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
+                // make sure all symbols lexically scoped by the block become valid again.
+                invalidatedSymbols.remove(symbol);
             }
         }
         return true;
@@ -1033,7 +1053,7 @@
 
         joinOnLabel(catchLabel);
         for(final CatchNode catchNode: tryNode.getCatches()) {
-            final IdentNode exception = catchNode.getException();
+            final IdentNode exception = catchNode.getExceptionIdentifier();
             onAssignment(exception, LvarType.OBJECT);
             final Expression condition = catchNode.getExceptionCondition();
             if(condition != null) {
@@ -1046,15 +1066,11 @@
             // throw an exception.
             reachable = true;
             catchBody.accept(this);
-            final Symbol exceptionSymbol = exception.getSymbol();
             if(reachable) {
-                localVariableTypes = cloneMap(localVariableTypes);
-                localVariableTypes.remove(exceptionSymbol);
                 jumpToLabel(catchBody, endLabel);
                 canExit = true;
             }
-            localVariableTypes = cloneMap(afterConditionTypes);
-            localVariableTypes.remove(exceptionSymbol);
+            localVariableTypes = afterConditionTypes;
         }
         // NOTE: if we had one or more conditional catch blocks with no unconditional catch block following them, then
         // there will be an unconditional rethrow, so the join point can never be reached from the last
@@ -1204,7 +1220,7 @@
     }
 
     private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) {
-        getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types);
+        getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this);
     }
 
     @Override
@@ -1226,16 +1242,18 @@
 
         boolean cloned = false;
         for(final Symbol symbol: block.getSymbols()) {
-            // Undefine the symbol outside the block
-            if(localVariableTypes.containsKey(symbol)) {
-                if(!cloned) {
-                    localVariableTypes = cloneMap(localVariableTypes);
-                    cloned = true;
-                }
-                localVariableTypes.remove(symbol);
-            }
-
             if(symbol.hasSlot()) {
+                // Invalidate the symbol when its defining block ends
+                if (symbol.isBytecodeLocal()) {
+                    if(localVariableTypes.containsKey(symbol)) {
+                        if(!cloned) {
+                            localVariableTypes = cloneMap(localVariableTypes);
+                            cloned = true;
+                        }
+                    }
+                    invalidateSymbol(symbol);
+                }
+
                 final SymbolConversions conversions = symbolConversions.get(symbol);
                 if(conversions != null) {
                     // Potentially make some currently dead types live if they're needed as a source of a type
@@ -1605,10 +1623,19 @@
         }
         assert symbol.hasSlot();
         assert !symbol.isGlobal();
-        localVariableTypes = localVariableTypes.isEmpty() ? new IdentityHashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+        cloneOrNewLocalVariableTypes();
         localVariableTypes.put(symbol, type);
     }
 
+    private void cloneOrNewLocalVariableTypes() {
+        localVariableTypes = localVariableTypes.isEmpty() ? new HashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+    }
+
+    private void invalidateSymbol(final Symbol symbol) {
+        localVariableTypes.remove(symbol);
+        invalidatedSymbols.add(symbol);
+    }
+
     /**
      * Set a flag in the symbol marking it as needing to be able to store a value of a particular type. Every symbol for
      * a local variable will be assigned between 1 and 6 local variable slots for storing all types it is known to need
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
index 06ffe2d..634b537 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
@@ -45,6 +45,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.DebuggerNode;
 import jdk.nashorn.internal.ir.EmptyNode;
@@ -60,9 +61,11 @@
 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.PrimitiveLiteralNode;
 import jdk.nashorn.internal.ir.LoopNode;
 import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.Statement;
@@ -70,6 +73,7 @@
 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;
@@ -78,6 +82,8 @@
 import jdk.nashorn.internal.parser.Token;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Source;
 import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -98,6 +104,7 @@
 
     private final DebugLogger log;
     private final boolean es6;
+    private final Source source;
 
     // Conservative pattern to test if element names consist of characters valid for identifiers.
     // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
@@ -146,6 +153,7 @@
 
         this.log = initLogger(compiler.getContext());
         this.es6 = compiler.getScriptEnvironment()._es6;
+        this.source = compiler.getSource();
     }
 
     @Override
@@ -170,6 +178,15 @@
     }
 
     @Override
+    public boolean enterCatchNode(final CatchNode catchNode) {
+        Expression exception = catchNode.getException();
+        if ((exception != null) && !(exception instanceof IdentNode)) {
+            throwNotImplementedYet("es6.destructuring", exception);
+        }
+        return true;
+    }
+
+    @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
         return addStatement(catchNode);
     }
@@ -241,6 +258,10 @@
             }
         }
 
+        if (es6 && expressionStatement.destructuringDeclarationType() != null) {
+            throwNotImplementedYet("es6.destructuring", expressionStatement);
+        }
+
         return addStatement(node);
     }
 
@@ -250,6 +271,14 @@
     }
 
     @Override
+    public boolean enterForNode(final ForNode forNode) {
+        if (es6 && (forNode.getInit() instanceof ObjectNode || forNode.getInit() instanceof ArrayLiteralNode)) {
+            throwNotImplementedYet("es6.destructuring", forNode);
+        }
+        return super.enterForNode(forNode);
+    }
+
+    @Override
     public Node leaveForNode(final ForNode forNode) {
         ForNode newForNode = forNode;
 
@@ -270,6 +299,37 @@
     }
 
     @Override
+    public boolean enterFunctionNode(final FunctionNode functionNode) {
+        if (es6) {
+            if (functionNode.getKind() == FunctionNode.Kind.MODULE) {
+                throwNotImplementedYet("es6.module", functionNode);
+            }
+
+            if (functionNode.getKind() == FunctionNode.Kind.GENERATOR) {
+                throwNotImplementedYet("es6.generator", functionNode);
+            }
+            if (functionNode.usesSuper()) {
+                throwNotImplementedYet("es6.super", functionNode);
+            }
+
+            final int numParams = functionNode.getNumOfParams();
+            if (numParams > 0) {
+                final IdentNode lastParam = functionNode.getParameter(numParams - 1);
+                if (lastParam.isRestParameter()) {
+                    throwNotImplementedYet("es6.rest.param", lastParam);
+                }
+            }
+            for (final IdentNode param : functionNode.getParameters()) {
+                if (param.isDestructuredParameter()) {
+                    throwNotImplementedYet("es6.destructuring", functionNode);
+                }
+            }
+        }
+
+        return super.enterFunctionNode(functionNode);
+    }
+
+    @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         log.info("END FunctionNode: ", functionNode.getName());
         return functionNode;
@@ -578,6 +638,29 @@
     }
 
     @Override
+    public boolean enterUnaryNode(final UnaryNode unaryNode) {
+        if (es6) {
+            if (unaryNode.isTokenType(TokenType.YIELD) ||
+                unaryNode.isTokenType(TokenType.YIELD_STAR)) {
+                throwNotImplementedYet("es6.yield", unaryNode);
+            } else if (unaryNode.isTokenType(TokenType.SPREAD_ARGUMENT) ||
+                       unaryNode.isTokenType(TokenType.SPREAD_ARRAY)) {
+                throwNotImplementedYet("es6.spread", unaryNode);
+            }
+        }
+
+        return super.enterUnaryNode(unaryNode);
+    }
+
+    @Override
+    public boolean enterASSIGN(BinaryNode binaryNode) {
+        if (es6 && (binaryNode.lhs() instanceof ObjectNode || binaryNode.lhs() instanceof ArrayLiteralNode)) {
+            throwNotImplementedYet("es6.destructuring", binaryNode);
+        }
+        return super.enterASSIGN(binaryNode);
+    }
+
+    @Override
     public Node leaveVarNode(final VarNode varNode) {
         addStatement(varNode);
         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION)
@@ -608,6 +691,12 @@
         return addStatement(withNode);
     }
 
+    @Override
+    public boolean enterClassNode(final ClassNode classNode) {
+        throwNotImplementedYet("es6.class", classNode);
+        return super.enterClassNode(classNode);
+    }
+
     /**
      * Given a function node that is a callee in a CallNode, replace it with
      * the appropriate marker function. This is used by {@link CodeGenerator}
@@ -766,4 +855,13 @@
         }
         return false;
     }
+
+    private void throwNotImplementedYet(final String msgId, final Node node) {
+        final long token = node.getToken();
+        final int line = source.getLine(node.getStart());
+        final int column = source.getColumn(node.getStart());
+        final String message = ECMAErrors.getMessage("unimplemented." + msgId);
+        final String formatted = ErrorManager.format(message, source, line, column, token);
+        throw new RuntimeException(formatted);
+    }
 }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
index 80ca3a5..9431f3b 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
@@ -35,8 +35,8 @@
 public final class CatchNode extends Statement {
     private static final long serialVersionUID = 1L;
 
-    /** Exception identifier. */
-    private final IdentNode exception;
+    /** Exception binding identifier or binding pattern. */
+    private final Expression exception;
 
     /** Exception condition. */
     private final Expression exceptionCondition;
@@ -52,21 +52,27 @@
      * @param lineNumber         lineNumber
      * @param token              token
      * @param finish             finish
-     * @param exception          variable name of exception
+     * @param exception          variable name or pattern of exception
      * @param exceptionCondition exception condition
      * @param body               catch body
      * @param isSyntheticRethrow true if this node is a synthetically generated rethrow node.
      */
-    public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception,
+    public CatchNode(final int lineNumber, final long token, final int finish, final Expression exception,
             final Expression exceptionCondition, final Block body, final boolean isSyntheticRethrow) {
         super(lineNumber, token, finish);
-        this.exception          = exception == null ? null : exception.setIsInitializedHere();
+        if (exception instanceof IdentNode) {
+            this.exception = ((IdentNode) exception).setIsInitializedHere();
+        } else if ((exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode)) {
+            this.exception = exception;
+        } else {
+            throw new IllegalArgumentException("invalid catch parameter");
+        }
         this.exceptionCondition = exceptionCondition;
-        this.body               = body;
+        this.body = body;
         this.isSyntheticRethrow = isSyntheticRethrow;
     }
 
-    private CatchNode(final CatchNode catchNode, final IdentNode exception, final Expression exceptionCondition,
+    private CatchNode(final CatchNode catchNode, final Expression exception, final Expression exceptionCondition,
             final Block body, final boolean isSyntheticRethrow) {
         super(catchNode);
         this.exception          = exception;
@@ -83,11 +89,10 @@
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterCatchNode(this)) {
             return visitor.leaveCatchNode(
-                setException((IdentNode)exception.accept(visitor)).
-                setExceptionCondition(exceptionCondition == null ? null : (Expression)exceptionCondition.accept(visitor)).
-                setBody((Block)body.accept(visitor)));
+                    setException((Expression) exception.accept(visitor)).
+                            setExceptionCondition(exceptionCondition == null ? null : (Expression) exceptionCondition.accept(visitor)).
+                            setBody((Block) body.accept(visitor)));
         }
-
         return this;
     }
 
@@ -109,14 +114,25 @@
     }
 
     /**
-     * Get the identifier representing the exception thrown
-     * @return the exception identifier
+     * Get the binding pattern representing the exception thrown
+     *
+     * @return the exception binding pattern
      */
-    public IdentNode getException() {
+    public Expression getException() {
         return exception;
     }
 
     /**
+     * Get the identifier representing the exception thrown
+     *
+     * @return the exception identifier
+     * @throws ClassCastException if exception set is not binding identifier
+     */
+    public IdentNode getExceptionIdentifier() {
+        return (IdentNode) exception;
+    }
+
+    /**
      * Get the exception condition for this catch block
      * @return the exception condition
      */
@@ -146,13 +162,19 @@
 
     /**
      * Resets the exception of a catch block
-     * @param exception new exception
+     *
+     * @param exception new exception which can be binding identifier or binding
+     * pattern
      * @return new catch node if changed, same otherwise
      */
-    public CatchNode setException(final IdentNode exception) {
+    public CatchNode setException(final Expression exception) {
         if (this.exception == exception) {
             return this;
         }
+        /*check if exception is legitimate*/
+        if (!((exception instanceof IdentNode) || (exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode))) {
+            throw new IllegalArgumentException("invalid catch parameter");
+        }
         return new CatchNode(this, exception, exceptionCondition, body, isSyntheticRethrow);
     }
 
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index bb8d61a..fccad15 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -397,7 +397,7 @@
 
     @Override
     public boolean enterVarNode(final VarNode varNode) {
-        sb.append("var ");
+        sb.append(varNode.isConst() ? "const " : varNode.isLet() ? "let " : "var ");
         varNode.getName().toString(sb, printTypes);
         printLocalVariableConversion(varNode.getName());
         final Node init = varNode.getInit();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 136e5e0..e3b1edb 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public final boolean enterUnaryNode(final UnaryNode unaryNode) {
+    public boolean enterUnaryNode(final UnaryNode unaryNode) {
         switch (unaryNode.tokenType()) {
         case ADD:
             return enterADD(unaryNode);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
index 6b890db..1d600df 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
@@ -47,13 +47,25 @@
     private final Global global;
 
 
-    ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
+    private ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
         super(global.getArrayIteratorPrototype(), $nasgenmap$);
         this.iteratedObject = iteratedObject instanceof ScriptObject ? (ScriptObject) iteratedObject : null;
         this.iterationKind = iterationKind;
         this.global = global;
     }
 
+    static ArrayIterator newArrayValueIterator(final Object iteratedObject) {
+        return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.VALUE, Global.instance());
+    }
+
+    static ArrayIterator newArrayKeyIterator(final Object iteratedObject) {
+        return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.KEY, Global.instance());
+    }
+
+    static ArrayIterator newArrayKeyValueIterator(final Object iteratedObject) {
+        return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.KEY_VALUE, Global.instance());
+    }
+
     /**
      * 22.1.5.2.1 %ArrayIteratorPrototype%.next()
      *
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
index 0d318ad..dc172a8 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
@@ -48,7 +48,6 @@
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
 import jdk.nashorn.api.scripting.ClassFilter;
@@ -2449,17 +2448,17 @@
     }
 
     @Override
-    public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+    public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = NashornCallSiteDescriptor.getOperand(desc);
         final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
 
         if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
             if (lexicalScope.hasOwnProperty(name)) {
-                return lexicalScope.findGetMethod(desc, request, operation);
+                return lexicalScope.findGetMethod(desc, request);
             }
         }
 
-        final GuardedInvocation invocation =  super.findGetMethod(desc, request, operation);
+        final GuardedInvocation invocation =  super.findGetMethod(desc, request);
 
         // We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
         // because those are invalidated per-key in the addBoundProperties method above.
@@ -3061,8 +3060,8 @@
         }
 
         @Override
-        protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
-            return filterInvocation(super.findGetMethod(desc, request, operation));
+        protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+            return filterInvocation(super.findGetMethod(desc, request));
         }
 
         @Override
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
index b469cf7..357689a 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
@@ -1726,7 +1726,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object entries(final Object self) {
-        return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+        return ArrayIterator.newArrayKeyValueIterator(self);
     }
 
     /**
@@ -1737,7 +1737,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object keys(final Object self) {
-        return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY, Global.instance());
+        return ArrayIterator.newArrayKeyIterator(self);
     }
 
     /**
@@ -1748,7 +1748,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE)
     public static Object values(final Object self) {
-        return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+        return ArrayIterator.newArrayValueIterator(self);
     }
 
     /**
@@ -1759,7 +1759,7 @@
      */
     @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
     public static Object getIterator(final Object self) {
-        return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+        return ArrayIterator.newArrayValueIterator(self);
     }
 
     /**
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
index 0f67ec4..bf5f68c 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
@@ -232,6 +232,17 @@
         return (NativeFloat32Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getFloat32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
index de3d0f0..0a46907 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
@@ -232,6 +232,17 @@
         return (NativeFloat64Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getFloat64ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
index 735e6a3..4700e27 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
@@ -225,6 +225,17 @@
         return (NativeInt16Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getInt16ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
index 7eacedc..4292985 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
@@ -224,6 +224,17 @@
         return (NativeInt32Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getInt32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
index 75fde20..13f0058 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
@@ -224,6 +224,17 @@
         return (NativeInt8Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getInt8ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
index 39ff22f..ac90b8b 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -37,7 +37,6 @@
 import java.util.Iterator;
 import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.lookup.Lookup;
@@ -365,7 +364,7 @@
 
         Object obj;
         if (func instanceof ScriptFunction) {
-            obj = ScriptRuntime.apply((ScriptFunction)func, adaptee);
+            obj = ScriptRuntime.apply((ScriptFunction)func, this);
         } else {
             obj = new NativeArray(0);
         }
@@ -473,11 +472,11 @@
     }
 
     @Override
-    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = NashornCallSiteDescriptor.getOperand(desc);
         if (overrides && super.hasOwnProperty(name)) {
             try {
-                final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
+                final GuardedInvocation inv = super.findGetMethod(desc, request);
                 if (inv != null) {
                     return inv;
                 }
@@ -486,11 +485,9 @@
             }
         }
 
-        switch(operation) {
-        case GET_PROPERTY:
-        case GET_ELEMENT:
+        if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
             return findHook(desc, __get__);
-        case GET_METHOD:
+        } else {
             final FindProperty find = adaptee.findProperty(__call__, true);
             if (find != null) {
                 final Object value = find.getObjectValue();
@@ -505,11 +502,7 @@
                 }
             }
             throw typeError("no.such.function", name, ScriptRuntime.safeToString(this));
-        default:
-            break;
         }
-
-        throw new AssertionError("should not reach here");
     }
 
     @Override
@@ -544,7 +537,7 @@
     private Object callAdaptee(final Object retValue, final String name, final Object... args) {
         final Object func = adaptee.get(name);
         if (func instanceof ScriptFunction) {
-            return ScriptRuntime.apply((ScriptFunction)func, adaptee, args);
+            return ScriptRuntime.apply((ScriptFunction)func, this, args);
         }
         return retValue;
     }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
index de0cabf..72d144f 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
@@ -25,6 +25,10 @@
 
 package jdk.nashorn.internal.objects;
 
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -40,9 +44,7 @@
 import java.util.Set;
 import java.util.concurrent.Callable;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.NamedOperation;
 import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.BeansLinker;
 import jdk.dynalink.beans.StaticClass;
 import jdk.dynalink.linker.GuardedInvocation;
@@ -97,6 +99,10 @@
                 });
     }
 
+    private static final Operation GET_METHOD   = GET.withNamespace(METHOD);
+    private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+    private static final Operation SET_PROPERTY = SET.withNamespace(PROPERTY);
+
     @SuppressWarnings("unused")
     private static ScriptObject get__proto__(final Object self) {
         // See ES6 draft spec: B.2.2.1.1 get Object.prototype.__proto__
@@ -782,7 +788,7 @@
         for(final String methodName: methodNames) {
             final MethodHandle method;
             try {
-                method = getBeanOperation(linker, StandardOperation.GET_METHOD, methodName, getterType, source);
+                method = getBeanOperation(linker, GET_METHOD, methodName, getterType, source);
             } catch(final IllegalAccessError e) {
                 // Presumably, this was a caller sensitive method. Ignore it and carry on.
                 continue;
@@ -794,7 +800,7 @@
             MethodHandle getter;
             if(readablePropertyNames.contains(propertyName)) {
                 try {
-                    getter = getBeanOperation(linker, StandardOperation.GET_PROPERTY, propertyName, getterType, source);
+                    getter = getBeanOperation(linker, GET_PROPERTY, propertyName, getterType, source);
                 } catch(final IllegalAccessError e) {
                     // Presumably, this was a caller sensitive method. Ignore it and carry on.
                     getter = Lookup.EMPTY_GETTER;
@@ -806,7 +812,7 @@
             MethodHandle setter;
             if(isWritable) {
                 try {
-                    setter = getBeanOperation(linker, StandardOperation.SET_PROPERTY, propertyName, setterType, source);
+                    setter = getBeanOperation(linker, SET_PROPERTY, propertyName, setterType, source);
                 } catch(final IllegalAccessError e) {
                     // Presumably, this was a caller sensitive method. Ignore it and carry on.
                     setter = Lookup.EMPTY_SETTER;
@@ -836,11 +842,11 @@
         }
     }
 
-    private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final StandardOperation operation,
+    private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final Operation operation,
             final String name, final MethodType methodType, final Object source) {
         final GuardedInvocation inv;
         try {
-            inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(new NamedOperation(operation, name), methodType, source), Bootstrap.getLinkerServices());
+            inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation.named(name), methodType, source), Bootstrap.getLinkerServices());
             assert passesGuard(source, inv.getGuard());
         } catch(RuntimeException|Error e) {
             throw e;
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
index 3bf1663..5dd1403 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -701,13 +701,9 @@
             }
 
             thisIndex = matcher.end();
-            if (thisIndex == string.length() && matcher.start() == matcher.end()) {
-                // Avoid getting empty match at end of string twice
-                break;
-            }
 
-            // ECMA 15.5.4.10 String.prototype.match(regexp)
-            if (thisIndex == previousLastIndex) {
+            // ECMA6 21.2.5.6 step 8.g.iv.5: If matchStr is empty advance index by one
+            if (matcher.start() == matcher.end()) {
                 setLastIndex(thisIndex + 1);
                 previousLastIndex = thisIndex + 1;
             } else {
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
index ec1619e..d91ffa4 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
@@ -42,7 +42,6 @@
 import java.util.Locale;
 import java.util.Set;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException;
@@ -127,15 +126,15 @@
 
     // This is to support length as method call as well.
     @Override
-    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final String name = NashornCallSiteDescriptor.getOperand(desc);
 
         // if str.length(), then let the bean linker handle it
-        if ("length".equals(name) && operation == StandardOperation.GET_METHOD) {
+        if ("length".equals(name) && NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
             return null;
         }
 
-        return super.findGetMethod(desc, request, operation);
+        return super.findGetMethod(desc, request);
     }
 
     // This is to provide array-like access to string characters without creating a NativeString wrapper.
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
index fb3a667..0dfd275 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
@@ -229,6 +229,17 @@
         return (NativeUint16Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getUint16ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
index 4d691b2..7b91eb2 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
@@ -244,6 +244,17 @@
         return (NativeUint32Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getUint32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
index 229099e..3b11a54 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
@@ -230,6 +230,17 @@
         return (NativeUint8Array)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getUint8ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
index 905d99f..2edf2a7 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
@@ -82,7 +82,6 @@
         private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
         private static final MethodHandle RINT_D   = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", double.class, double.class).methodHandle();
         private static final MethodHandle RINT_O   = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", Object.class, Object.class).methodHandle();
-        private static final MethodHandle CLAMP_LONG = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "clampLong", long.class, long.class).methodHandle();
 
         private Uint8ClampedArrayData(final ByteBuffer nb, final int start, final int end) {
             super((nb.position(start).limit(end)).slice(), end - start);
@@ -124,8 +123,6 @@
                     return MH.filterArguments(setter, 2, RINT_O);
                 } else if (elementType == double.class) {
                     return MH.filterArguments(setter, 2, RINT_D);
-                } else if (elementType == long.class) {
-                    return MH.filterArguments(setter, 2, CLAMP_LONG);
                 }
             }
             return setter;
@@ -195,7 +192,7 @@
 
         @Override
         public ArrayData set(final int index, final double value, final boolean strict) {
-            return set(index, rint(value), strict);
+            return set(index, (int) rint(value), strict);
         }
 
         private static double rint(final double rint) {
@@ -207,15 +204,6 @@
             return rint(JSType.toNumber(rint));
         }
 
-        @SuppressWarnings("unused")
-        private static long clampLong(final long l) {
-            if(l < 0L) {
-                return 0L;
-            } else if(l > 0xffL) {
-                return 0xffL;
-            }
-            return l;
-        }
     }
 
     /**
@@ -278,6 +266,17 @@
         return (NativeUint8ClampedArray)ArrayBufferView.subarrayImpl(self, begin, end);
     }
 
+    /**
+     * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+     *
+     * @param self the self reference
+     * @return an iterator over the array's values
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+    public static Object getIterator(final Object self) {
+        return ArrayIterator.newArrayValueIterator(self);
+    }
+
     @Override
     protected ScriptObject getPrototype(final Global global) {
         return global.getUint8ClampedArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
index 3b43249..2451822 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
@@ -102,19 +102,9 @@
 
     private int templateExpressionOpenBraces;
 
-    private static final String SPACETAB = " \t";  // ASCII space and tab
-    private static final String LFCR     = "\n\r"; // line feed and carriage return (ctrl-m)
-
-    private static final String JAVASCRIPT_WHITESPACE_EOL =
-        LFCR +
+    private static final String JAVASCRIPT_OTHER_WHITESPACE =
         "\u2028" + // line separator
-        "\u2029"   // paragraph separator
-        ;
-    private static final String JAVASCRIPT_WHITESPACE =
-        SPACETAB +
-        JAVASCRIPT_WHITESPACE_EOL +
-        "\u000b" + // tabulation line
-        "\u000c" + // ff (ctrl-l)
+        "\u2029" + // paragraph separator
         "\u00a0" + // Latin-1 space
         "\u1680" + // Ogham space mark
         "\u180e" + // separator, Mongolian vowel
@@ -384,7 +374,13 @@
      * @return true if valid JavaScript whitespace
      */
     public static boolean isJSWhitespace(final char ch) {
-        return JAVASCRIPT_WHITESPACE.indexOf(ch) != -1;
+        return ch == ' '                  // space
+            || ch >= '\t' && ch <= '\r'   // 0x09..0x0d: tab, line feed, tabulation line, ff, carriage return
+            || ch >= 160 && isOtherJSWhitespace(ch);
+    }
+
+    private static boolean isOtherJSWhitespace(final char ch) {
+        return JAVASCRIPT_OTHER_WHITESPACE.indexOf(ch) != -1;
     }
 
     /**
@@ -393,7 +389,10 @@
      * @return true if valid JavaScript end of line
      */
     public static boolean isJSEOL(final char ch) {
-        return JAVASCRIPT_WHITESPACE_EOL.indexOf(ch) != -1;
+        return ch == '\n'      // line feed
+            || ch == '\r'      // carriage return (ctrl-m)
+            || ch == '\u2028'  // line separator
+            || ch == '\u2029'; // paragraph separator
     }
 
     /**
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
index 5dfa469..fb4fd43 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
@@ -1962,6 +1962,18 @@
             switch (type) {
             case SEMICOLON:
                 // for (init; test; modify)
+                if (varDeclList != null) {
+                    assert init == null;
+                    init = varDeclList.init;
+                    // late check for missing assignment, now we know it's a for (init; test; modify) loop
+                    if (varDeclList.missingAssignment != null) {
+                        if (varDeclList.missingAssignment instanceof IdentNode) {
+                            throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)varDeclList.missingAssignment).getName()));
+                        } else {
+                            throw error(AbstractParser.message("missing.destructuring.assignment"), varDeclList.missingAssignment.getToken());
+                        }
+                    }
+                }
 
                 // for each (init; test; modify) is invalid
                 if ((flags & ForNode.IS_FOR_EACH) != 0) {
@@ -2607,13 +2619,23 @@
                 next();
                 expect(LPAREN);
 
-                // FIXME: ES6 catch parameter can be a BindingIdentifier or a BindingPattern
-                // We need to generalize this here!
+                // ES6 catch parameter can be a BindingIdentifier or a BindingPattern
                 // http://www.ecma-international.org/ecma-262/6.0/
-                final IdentNode exception = getIdent();
+                final String contextString = "catch argument";
+                final Expression exception = bindingIdentifierOrPattern(contextString);
+                final boolean isDestructuring = !(exception instanceof IdentNode);
+                if (isDestructuring) {
+                    verifyDestructuringBindingPattern(exception, new Consumer<IdentNode>() {
+                        @Override
+                        public void accept(final IdentNode identNode) {
+                            verifyIdent(identNode, contextString);
+                        }
+                    });
+                } else {
+                    // ECMA 12.4.1 strict mode restrictions
+                    verifyStrictIdent((IdentNode) exception, "catch argument");
+                }
 
-                // ECMA 12.4.1 strict mode restrictions
-                verifyStrictIdent(exception, "catch argument");
 
                 // Nashorn extension: catch clause can have optional
                 // condition. So, a single try can have more than one
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
index 71f7728..3a238dc 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -67,7 +67,6 @@
 import java.util.concurrent.atomic.LongAdder;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -1858,23 +1857,16 @@
      * @return GuardedInvocation for the callsite
      */
     public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
-        // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
-        // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
+        // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
+        // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are
         // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
         // operation has an associated name or not.
-        final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
-        if (op == null) {
-            return null;
-        }
-        switch (op) {
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-        case GET_METHOD:
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+        case GET:
             return desc.getOperation() instanceof NamedOperation
-                    ? findGetMethod(desc, request, op)
+                    ? findGetMethod(desc, request)
                     : findGetIndexMethod(desc, request);
-        case SET_PROPERTY:
-        case SET_ELEMENT:
+        case SET:
             return desc.getOperation() instanceof NamedOperation
                     ? findSetMethod(desc, request)
                     : findSetIndexMethod(desc, request);
@@ -1883,8 +1875,8 @@
         case NEW:
             return findNewMethod(desc, request);
         default:
+            return null;
         }
-        return null;
     }
 
     /**
@@ -1952,11 +1944,10 @@
      *
      * @param desc     the call site descriptor
      * @param request  the link request
-     * @param operation operation for get: getProp, getMethod, getElem etc
      *
      * @return GuardedInvocation to be invoked at call site.
      */
-    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+    protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
         final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
 
         String name = NashornCallSiteDescriptor.getOperand(desc);
@@ -1967,21 +1958,17 @@
         }
 
         if (request.isCallSiteUnstable() || hasWithScope()) {
-            return findMegaMorphicGetMethod(desc, name, operation == StandardOperation.GET_METHOD);
+            return findMegaMorphicGetMethod(desc, name, NashornCallSiteDescriptor.isMethodFirstOperation(desc));
         }
 
         final FindProperty find = findProperty(name, true, NashornCallSiteDescriptor.isScope(desc), this);
         MethodHandle mh;
 
         if (find == null) {
-            switch (operation) {
-            case GET_ELEMENT: // getElem only gets here if element name is constant, so treat it like a property access
-            case GET_PROPERTY:
+            if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
                 return noSuchProperty(desc, request);
-            case GET_METHOD:
+            } else {
                 return noSuchMethod(desc, request);
-            default:
-                throw new AssertionError(operation); // never invoked with any other operation
             }
         }
 
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
index ac1aca5..48a9f92 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
@@ -32,7 +32,6 @@
 import java.lang.invoke.MethodHandles;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.support.Guards;
 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -93,29 +92,22 @@
      * @return GuardedInvocation to be invoked at call site.
      */
     public static GuardedInvocation lookup(final CallSiteDescriptor desc) {
-        final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
-        if (op == null) {
-            return null;
-        }
-        switch (op) {
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
         case CALL:
         case NEW:
             final String name = NashornCallSiteDescriptor.getOperand(desc);
             final String msg = name != null? "not.a.function" : "cant.call.undefined";
             throw typeError(msg, name);
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-        case GET_METHOD:
-            // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
-            // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
+        case GET:
+            // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
+            // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are
             // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
             // operation has an associated name or not.
             if (!(desc.getOperation() instanceof NamedOperation)) {
                 return findGetIndexMethod(desc);
             }
             return findGetMethod(desc);
-        case SET_PROPERTY:
-        case SET_ELEMENT:
+        case SET:
             if (!(desc.getOperation() instanceof NamedOperation)) {
                 return findSetIndexMethod(desc);
             }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
index 8caa260..f58fc7d 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
@@ -97,9 +97,6 @@
             return super.lookup(desc, request);
         }
 
-        // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
-        // necessity have a Nashorn descriptor - it is safe to cast.
-        final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
         GuardedInvocation link = null;
         final Operation op = desc.getOperation();
 
@@ -111,7 +108,7 @@
         if (find != null) {
             link = expression.lookup(desc, request);
             if (link != null) {
-                return fixExpressionCallSite(ndesc, link);
+                return fixExpressionCallSite(desc, link);
             }
         }
 
@@ -126,39 +123,30 @@
         // __noSuchProperty__ and __noSuchMethod__ in expression
         final String fallBack;
 
-        final StandardOperation firstOp = ndesc.getFirstOperation();
-        switch (firstOp) {
-        case GET_METHOD:
-            fallBack = NO_SUCH_METHOD_NAME;
-            break;
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-            fallBack = NO_SUCH_PROPERTY_NAME;
-            break;
-        default:
+        final Operation firstOp = NashornCallSiteDescriptor.getBaseOperation(desc);
+        if (firstOp == StandardOperation.GET) {
+            if (NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
+                fallBack = NO_SUCH_METHOD_NAME;
+            } else {
+                fallBack = NO_SUCH_PROPERTY_NAME;
+            }
+        } else {
             fallBack = null;
-            break;
         }
 
         if (fallBack != null) {
             find = expression.findProperty(fallBack, true);
             if (find != null) {
-                switch (firstOp) {
-                case GET_METHOD:
+                if (NO_SUCH_METHOD_NAME.equals(fallBack)) {
                     link = expression.noSuchMethod(desc, request);
-                    break;
-                case GET_PROPERTY:
-                case GET_ELEMENT:
+                } else if (NO_SUCH_PROPERTY_NAME.equals(fallBack)) {
                     link = expression.noSuchProperty(desc, request);
-                    break;
-                default:
-                    break;
                 }
             }
         }
 
         if (link != null) {
-            return fixExpressionCallSite(ndesc, link);
+            return fixExpressionCallSite(desc, link);
         }
 
         // still not found, may be scope can handle with it's own
@@ -245,10 +233,10 @@
         return link.asType(newInvType);
     }
 
-    private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
+    private static GuardedInvocation fixExpressionCallSite(final CallSiteDescriptor 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 (desc.getFirstOperation() != StandardOperation.GET_METHOD) {
+        if (NashornCallSiteDescriptor.getBaseOperation(desc) != StandardOperation.GET || !NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
             return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
         }
 
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
index 621f789..3578ed8 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
@@ -35,7 +35,6 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
 import jdk.dynalink.linker.LinkerServices;
@@ -91,24 +90,17 @@
             inv = null;
         }
 
-        final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
-        if (op == null) {
-            return inv;
-        }
         final String name = NashornCallSiteDescriptor.getOperand(desc);
-        switch (op) {
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-        case GET_METHOD:
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+        case GET:
             return name != null ? findGetMethod(name, inv) : findGetIndexMethod(inv);
-        case SET_PROPERTY:
-        case SET_ELEMENT:
+        case SET:
             return name != null ? findSetMethod(name, inv) : findSetIndexMethod();
         case CALL:
             return findCallMethod(desc);
         default:
+            return null;
         }
-        return null;
     }
 
     private static GuardedInvocation findGetMethod(final String name, final GuardedInvocation inv) {
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index 7471cc4..af6de32 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -33,6 +33,7 @@
 import java.util.Map;
 import javax.script.Bindings;
 import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.Operation;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
@@ -92,29 +93,31 @@
     }
 
     private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception {
-        final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
-        if (op == null) {
-            return null;
-        }
-        final String name = NashornCallSiteDescriptor.getOperand(desc);
-        switch (op) {
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-        case GET_METHOD:
-            if (name != null) {
-                return findGetMethod(name);
+        final Operation op = NashornCallSiteDescriptor.getBaseOperation(desc);
+        if (op instanceof StandardOperation) {
+            final String name = NashornCallSiteDescriptor.getOperand(desc);
+            switch ((StandardOperation)op) {
+            case GET:
+                if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) {
+                    if (name != null) {
+                        return findGetMethod(name);
+                    }
+                    // For indexed get, we want get GuardedInvocation beans linker and pass it.
+                    // JSObjectLinker.get uses this fallback getter for explicit signature method access.
+                    return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
+                }
+                break;
+            case SET:
+                if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) {
+                    return name != null ? findSetMethod(name) : findSetIndexMethod();
+                }
+                break;
+            case CALL:
+                return findCallMethod(desc);
+            case NEW:
+                return findNewMethod(desc);
+            default:
             }
-            // For indexed get, we want get GuardedInvocation beans linker and pass it.
-            // JSObjectLinker.get uses this fallback getter for explicit signature method access.
-            return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
-        case SET_PROPERTY:
-        case SET_ELEMENT:
-            return name != null ? findSetMethod(name) : findSetIndexMethod();
-        case CALL:
-            return findCallMethod(desc);
-        case NEW:
-            return findNewMethod(desc);
-        default:
         }
         return null;
     }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
index 6629b1a..8d525a7 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
@@ -25,15 +25,15 @@
 
 package jdk.nashorn.internal.runtime.linker;
 
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardOperation.GET;
 import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX;
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.NamedOperation;
 import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.BeansLinker;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
@@ -61,6 +61,8 @@
         IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
     }
 
+    private static final Operation GET_METHOD = GET.withNamespace(METHOD);
+
     private final BeansLinker beansLinker;
 
     JavaSuperAdapterLinker(final BeansLinker beansLinker) {
@@ -82,8 +84,8 @@
 
         final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
 
-        if(!NashornCallSiteDescriptor.contains(descriptor, StandardOperation.GET_METHOD)) {
-            // We only handle GET_METHOD
+        if(!NashornCallSiteDescriptor.contains(descriptor, GET, METHOD)) {
+            // We only handle GET:METHOD
             return null;
         }
 
@@ -97,8 +99,7 @@
         final MethodType type = descriptor.getMethodType();
         final Class<?> adapterClass = adapter.getClass();
         final String name = NashornCallSiteDescriptor.getOperand(descriptor);
-        final Operation newOp = name == null ? StandardOperation.GET_METHOD :
-            new NamedOperation(StandardOperation.GET_METHOD, SUPER_PREFIX + name);
+        final Operation newOp = name == null ? GET_METHOD : GET_METHOD.named(SUPER_PREFIX + name);
 
         final CallSiteDescriptor newDescriptor = new CallSiteDescriptor(
                 NashornCallSiteDescriptor.getLookupInternal(descriptor), newOp,
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
index d2a46ea..ac2f7cb 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
@@ -35,7 +35,9 @@
 import java.util.function.Supplier;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Operation;
 import jdk.dynalink.SecureLookupSupplier;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.BeansLinker;
 import jdk.dynalink.linker.ConversionComparator.Comparison;
@@ -46,6 +48,7 @@
 import jdk.dynalink.linker.MethodHandleTransformer;
 import jdk.dynalink.linker.support.DefaultInternalObjectFilter;
 import jdk.dynalink.linker.support.Lookup;
+import jdk.dynalink.linker.support.SimpleLinkRequest;
 import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
@@ -68,6 +71,9 @@
     // Object type arguments of Java method calls, field set and array set.
     private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
 
+    private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD);
+    private static final MethodType GET_METHOD_TYPE = MethodType.methodType(Object.class, Object.class);
+
     private static final MethodHandle EXPORT_ARGUMENT;
     private static final MethodHandle IMPORT_RESULT;
     private static final MethodHandle FILTER_CONSSTRING;
@@ -114,20 +120,38 @@
             // those are script functions.
             final String name = getFunctionalInterfaceMethodName(self.getClass());
             if (name != null) {
-                final MethodType callType = desc.getMethodType();
-                // drop callee (Undefined ScriptFunction) and change the request to be CALL_METHOD:<name>
-                final CallSiteDescriptor newDesc = new CallSiteDescriptor(
+                // Obtain the method
+                final CallSiteDescriptor getMethodDesc = new CallSiteDescriptor(
                         NashornCallSiteDescriptor.getLookupInternal(desc),
-                        new NamedOperation(StandardOperation.CALL_METHOD, name),
-                        desc.getMethodType().dropParameterTypes(1, 2));
-                final GuardedInvocation gi = getGuardedInvocation(beansLinker,
-                        linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
+                        GET_METHOD.named(name), GET_METHOD_TYPE);
+                final GuardedInvocation getMethodInv = linkerServices.getGuardedInvocation(
+                        new SimpleLinkRequest(getMethodDesc, false, self));
+                final Object method;
+                try {
+                    method = getMethodInv.getInvocation().invokeExact(self);
+                } catch (final Exception|Error e) {
+                    throw e;
+                } catch (final Throwable t) {
+                    throw new RuntimeException(t);
+                }
+
+                final Object[] args = linkRequest.getArguments();
+                args[1] = args[0]; // callee (the functional object) becomes this
+                args[0] = method; // the method becomes the callee
+
+                final MethodType callType = desc.getMethodType();
+
+                final CallSiteDescriptor newDesc = desc.changeMethodType(
+                        desc.getMethodType().changeParameterType(0, Object.class).changeParameterType(1, callType.parameterType(0)));
+                final GuardedInvocation gi = getGuardedInvocation(beansLinker, linkRequest.replaceArguments(newDesc, args),
                         new NashornBeansLinkerServices(linkerServices));
 
-                // drop 'thiz' passed from the script.
-                return gi.replaceMethods(
-                    MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
-                    gi.getGuard());
+                // Bind to the method, drop the original "this" and use original "callee" as this:
+                final MethodHandle inv = linkerServices.filterInternalObjects(gi
+                        .getInvocation()  // (method, this, args...)
+                        .bindTo(method)); // (this, args...)
+                final MethodHandle calleeToThis = MH.dropArguments(inv, 1, callType.parameterType(1)); // (callee->this, <drop>, args...)
+                return gi.replaceMethods(calleeToThis, gi.getGuard());
             }
         }
         return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
index d977129..bd4ab24 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
@@ -38,7 +38,6 @@
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.NamedOperation;
 import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.BeansLinker;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -98,7 +97,7 @@
     private static GuardedInvocation linkBean(final LinkRequest linkRequest) throws Exception {
         final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
         final Object self = linkRequest.getReceiver();
-        switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
         case NEW:
             if(BeansLinker.isDynamicConstructor(self)) {
                 throw typeError("no.constructor.matches.args", ScriptRuntime.safeToString(self));
@@ -124,35 +123,26 @@
 
     static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
         final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
-        final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
-        if (op != null) {
-            final String operand = NashornCallSiteDescriptor.getOperand(desc);
-            switch (op) {
-            case GET_METHOD:
-            case GET_PROPERTY:
-            case GET_ELEMENT: {
-                if (NashornCallSiteDescriptor.isOptimistic(desc)) {
-                    return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
-                }
-                if (NashornCallSiteDescriptor.getOperand(desc) != null) {
-                    return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
-                }
-                return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
+        final String operand = NashornCallSiteDescriptor.getOperand(desc);
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+        case GET:
+            if (NashornCallSiteDescriptor.isOptimistic(desc)) {
+                return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
+            } else if (operand != null) {
+                return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
             }
-            case SET_PROPERTY:
-            case SET_ELEMENT:
-                final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
-                if (strict) {
-                    return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
-                }
-                if (NashornCallSiteDescriptor.getOperand(desc) != null) {
-                    return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
-                }
-                return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
-            default:
+            return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
+        case SET:
+            final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
+            if (strict) {
+                return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
+            } else if (operand != null) {
+                return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
             }
+            return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
+        default:
+            throw new AssertionError("unknown call type " + desc);
         }
-        throw new AssertionError("unknown call type " + desc);
     }
 
     private static MethodHandle bindOperand(final MethodHandle handle, final String operand) {
@@ -217,17 +207,13 @@
 
     private static GuardedInvocation linkNull(final LinkRequest linkRequest) {
         final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
-        switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
         case NEW:
         case CALL:
             throw typeError("not.a.function", "null");
-        case GET_METHOD:
-            throw typeError("no.such.function", getArgument(linkRequest), "null");
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-            throw typeError("cant.get.property", getArgument(linkRequest), "null");
-        case SET_PROPERTY:
-        case SET_ELEMENT:
+        case GET:
+            throw typeError(NashornCallSiteDescriptor.isMethodFirstOperation(desc) ? "no.such.function" : "cant.get.property", getArgument(linkRequest), "null");
+        case SET:
             throw typeError("cant.set.property", getArgument(linkRequest), "null");
         default:
             throw new AssertionError("unknown call type " + desc);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
index 25999d1..71f9f47 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
@@ -25,6 +25,12 @@
 
 package jdk.nashorn.internal.runtime.linker;
 
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
+
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
@@ -40,10 +46,11 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Stream;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.Operation;
 import jdk.dynalink.SecureLookupSupplier;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.nashorn.internal.ir.debug.NashornTextifier;
 import jdk.nashorn.internal.runtime.AccessControlContextFactory;
@@ -78,12 +85,12 @@
 
     // Correspond to the operation indices above.
     private static final Operation[] OPERATIONS = new Operation[] {
-        new CompositeOperation(StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT, StandardOperation.GET_METHOD),
-        new CompositeOperation(StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY, StandardOperation.GET_METHOD),
-        new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT),
-        new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY),
-        new CompositeOperation(StandardOperation.SET_PROPERTY, StandardOperation.SET_ELEMENT),
-        new CompositeOperation(StandardOperation.SET_ELEMENT, StandardOperation.SET_PROPERTY),
+        GET.withNamespaces(PROPERTY, ELEMENT, METHOD),
+        GET.withNamespaces(ELEMENT, PROPERTY, METHOD),
+        GET.withNamespaces(METHOD, PROPERTY, ELEMENT),
+        GET.withNamespaces(METHOD, ELEMENT, PROPERTY),
+        SET.withNamespaces(PROPERTY, ELEMENT),
+        SET.withNamespaces(ELEMENT, PROPERTY),
         StandardOperation.CALL,
         StandardOperation.NEW
     };
@@ -248,7 +255,7 @@
                 return existing;
             }
         }
-        final NamedOperation newOp = new NamedOperation(baseOp, name);
+        final NamedOperation newOp = baseOp.named(name);
         namedOps.put(name, new WeakReference<>(newOp));
         return newOp;
     }
@@ -288,16 +295,6 @@
     }
 
     /**
-     * Returns the named operand in this descriptor's operation. Equivalent to
-     * {@code ((NamedOperation)getOperation()).getName().toString()} for call
-     * sites with a named operand. For call sites without named operands returns null.
-     * @return the named operand in this descriptor's operation.
-     */
-    public String getOperand() {
-        return getOperand(this);
-    }
-
-    /**
      * Returns the named operand in the passed descriptor's operation.
      * Equivalent to
      * {@code ((NamedOperation)desc.getOperation()).getName().toString()} for
@@ -311,70 +308,63 @@
         return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null;
     }
 
-    /**
-     * Returns the first operation in this call site descriptor's potentially
-     * composite operation. E.g. if this call site descriptor has a composite
-     * operation {@code GET_PROPERTY|GET_METHOD|GET_ELEM}, it will return
-     * {@code GET_PROPERTY}. Nashorn - being a ECMAScript engine - does not
-     * distinguish between property, element, and method namespace; ECMAScript
-     * objects just have one single property namespace for all these, therefore
-     * it is largely irrelevant what the composite operation is structured like;
-     * if the first operation can't be satisfied, neither can the others. The
-     * first operation is however sometimes used to slightly alter the
-     * semantics; for example, a distinction between {@code GET_PROPERTY} and
-     * {@code GET_METHOD} being the first operation can translate into whether
-     * {@code "__noSuchProperty__"} or {@code "__noSuchMethod__"} will be
-     * executed in case the property is not found. Note that if a call site
-     * descriptor comes from outside of Nashorn, its class will be different,
-     * and there is no guarantee about the way it composes its operations. For
-     * that reason, for potentially foreign call site descriptors you should use
-     * {@link #getFirstStandardOperation(CallSiteDescriptor)} instead.
-     * @return the first operation in this call site descriptor. Note this will
-     * always be a {@code StandardOperation} as Nashorn internally only uses
-     * standard operations.
-     */
-    public StandardOperation getFirstOperation() {
-        final Operation base = NamedOperation.getBaseOperation(getOperation());
-        if (base instanceof CompositeOperation) {
-            return (StandardOperation)((CompositeOperation)base).getOperation(0);
-        }
-        return (StandardOperation)base;
+    private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) {
+        return StandardNamespace.findFirst(desc.getOperation());
     }
 
     /**
-     * Returns the first standard operation in the (potentially composite)
-     * operation of the passed call site descriptor.
+     * Returns true if the operation of the call descriptor is operating on the method namespace first.
+     * @param desc the call descriptor in question.
+     * @return true if the operation of the call descriptor is operating on the method namespace first.
+     */
+    public static boolean isMethodFirstOperation(final CallSiteDescriptor desc) {
+        return findFirstStandardNamespace(desc) == StandardNamespace.METHOD;
+    }
+
+    /**
+     * Returns true if there's a namespace operation in the call descriptor and it is operating on at least
+     * one {@link StandardNamespace}. This method is only needed for exported linkers, since internal linkers
+     * always operate on Nashorn-generated call sites, and they always operate on standard namespaces only.
+     * @param desc the call descriptor in question.
+     * @return true if the operation of the call descriptor is operating on at least one standard namespace.
+     */
+    public static boolean hasStandardNamespace(final CallSiteDescriptor desc) {
+        return findFirstStandardNamespace(desc) != null;
+    }
+
+    /**
+     * Returns the base operation in this call site descriptor after unwrapping it from both a named operation
+     * and a namespace operation.
      * @param desc the call site descriptor.
-     * @return Returns the first standard operation in the (potentially
-     * composite) operation of the passed call site descriptor. Can return null
-     * if the call site contains no standard operations.
+     * @return the base operation in this call site descriptor.
      */
-    public static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
-        final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
-        if (base instanceof StandardOperation) {
-            return (StandardOperation)base;
-        } else if (base instanceof CompositeOperation) {
-            final CompositeOperation cop = (CompositeOperation)base;
-            for(int i = 0; i < cop.getOperationCount(); ++i) {
-                final Operation op = cop.getOperation(i);
-                if (op instanceof StandardOperation) {
-                    return (StandardOperation)op;
-                }
-            }
-        }
-        return null;
+    public static Operation getBaseOperation(final CallSiteDescriptor desc) {
+        return NamespaceOperation.getBaseOperation(NamedOperation.getBaseOperation(desc.getOperation()));
     }
 
     /**
-     * Returns true if the passed call site descriptor's operation contains (or
-     * is) the specified standard operation.
+     * Returns the standard operation that is the base operation in this call site descriptor.
+     * @param desc the call site descriptor.
+     * @return the standard operation that is the base operation in this call site descriptor.
+     * @throws ClassCastException if the base operation is not a standard operation. This method is only
+     * safe to use when the base operation is known to be a standard operation (e.g. all Nashorn call sites
+     * are such, so it's safe to use from internal linkers).
+     */
+    public static StandardOperation getStandardOperation(final CallSiteDescriptor desc) {
+        return (StandardOperation)getBaseOperation(desc);
+    }
+
+    /**
+     * Returns true if the passed call site descriptor contains the specified standard operation on the
+     * specified standard namespace.
      * @param desc the call site descriptor.
      * @param operation the operation whose presence is tested.
-     * @return Returns true if the call site descriptor's operation contains (or
-     * is) the specified standard operation.
+     * @param namespace the namespace on which the operation operates.
+     * @return Returns true if the call site descriptor contains the specified standard operation on the
+     * specified standard namespace.
      */
-    public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation) {
-        return CompositeOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation);
+    public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation, final StandardNamespace namespace) {
+        return NamespaceOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation, namespace);
     }
 
     /**
@@ -383,8 +373,8 @@
      * @param obj object on which CALL or NEW is used
      * @return error message
      */
-    public String getFunctionErrorMessage(final Object obj) {
-        final String funcDesc = getOperand();
+    private String getFunctionErrorMessage(final Object obj) {
+        final String funcDesc = getOperand(this);
         return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj);
     }
 
@@ -552,4 +542,9 @@
     public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
         return get(getLookupPrivileged(), getOperation(), newMethodType, flags);
     }
+
+    @Override
+    protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
+        return get(getLookupPrivileged(), newOperation, getMethodType(), flags);
+    }
 }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
index 4a7c8d7..5a321d0 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
@@ -99,10 +99,8 @@
         final String name = NashornCallSiteDescriptor.getOperand(desc);
         final FindProperty find = name != null ? wrappedReceiver.findProperty(name, true) : null;
 
-        switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
-        case GET_PROPERTY:
-        case GET_ELEMENT:
-        case GET_METHOD:
+        switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+        case GET:
             //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
             //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
             //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
@@ -133,8 +131,7 @@
                 }
             }
             break;
-        case SET_PROPERTY:
-        case SET_ELEMENT:
+        case SET:
             return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc));
         default:
             break;
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
index 7c94ebc..a168fe1 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
@@ -30,6 +30,7 @@
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
 import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.linker.LinkRequest;
@@ -129,9 +130,9 @@
             // allow 'static' access on Class objects representing public classes of non-restricted packages
             if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
                 final CallSiteDescriptor desc = request.getCallSiteDescriptor();
-                if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET_PROPERTY)) {
+                if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET, StandardNamespace.PROPERTY)) {
                     if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) {
-                        // If "GET_PROPERTY:static" passes access checks, allow access.
+                        // If "GET:PROPERTY:static" passes access checks, allow access.
                         return;
                     }
                 }
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
index 0116fb4..2c84781 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -214,6 +214,7 @@
 syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
 syntax.error.redeclare.variable=Variable "{0}" has already been declared
 syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
+syntax.error.duplicate.parameter=Duplicate parameter name "{0}"
 
 io.error.cant.write=cannot write "{0}"
 
@@ -222,3 +223,12 @@
 
 uri.error.bad.uri=Bad URI "{0}" near offset {1}
 list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context.
+
+unimplemented.es6.module=ES6 modules are not yet implemented
+unimplemented.es6.rest.param=ES6 function rest parameter declaration is not yet implemented
+unimplemented.es6.yield=ES6 yield and yield* are not yet implemented
+unimplemented.es6.spread=ES6 spread operator is not yet implemented
+unimplemented.es6.class=ES6 class declarations and expressions are not yet implemented
+unimplemented.es6.destructuring=ES6 destructuring is not yet implemented
+unimplemented.es6.generator=ES6 generator is not yet implemented
+unimplemented.es6.super=ES6 super keyword is not yet implemented
diff --git a/test/script/basic/JDK-8164708.js b/test/script/basic/JDK-8164708.js
new file mode 100644
index 0000000..d477d9c
--- /dev/null
+++ b/test/script/basic/JDK-8164708.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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-8164708: String.prototype.replace replaces empty match twice
+ *
+ * @test
+ * @run
+ */
+
+Assert.assertEquals("4005".replace(/\B(?=(\d{3})+(?!\d))/g, ","), "4,005");
+
diff --git a/test/script/basic/JDK-8168146.js b/test/script/basic/JDK-8168146.js
new file mode 100644
index 0000000..dc96e96
--- /dev/null
+++ b/test/script/basic/JDK-8168146.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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-8168146: Infinite recursion in Uint8ClampedArray.set
+ *
+ * @test
+ * @run
+ */
+
+
+var a = new Uint8ClampedArray(10);
+
+for (var i = 0; i < 10; i++) {
+    a[i] = i;
+    Assert.assertTrue(a[i] === i);
+}
diff --git a/test/script/basic/es6/JDK-8168140.js b/test/script/basic/es6/JDK-8168140.js
new file mode 100644
index 0000000..c94c704
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168140.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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-8168140: TypedArrays should implement ES6 iterator protocol
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+let TypedArrayTypes = [
+    Int8Array,
+    Uint8Array,
+    Uint8ClampedArray,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+];
+
+let arrays = [];
+let sum = 0;
+
+TypedArrayTypes.forEach(function(ArrayType) {
+    var a = new ArrayType(10);
+    for (let i = 0; i < a.length; i++) {
+        a[i] = i;
+    }
+    arrays.push(a);
+});
+
+Assert.assertTrue(arrays.length === 9);
+
+for (let array of arrays) {
+
+    Assert.assertTrue(array.length === 10);
+    let count = 0;
+
+    for (let value of array) {
+        Assert.assertTrue(value === count++);
+        sum += value;
+    }
+}
+
+Assert.assertTrue(sum === 405);
diff --git a/test/script/basic/es6/JDK-8168373.js b/test/script/basic/es6/JDK-8168373.js
new file mode 100644
index 0000000..af26e73
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168373.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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-8168373: don't emit conversions for symbols outside their lexical scope
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function p() { return false } // "predicate"
+function r(x) { return x } // "read"
+
+(function() {
+  try { // Try creates control flow edges from assignments into catch blocks.
+    // Lexically scoped, never read int variable (undefined at catch block) but still with a cf edge into catch block.
+    // Since it's never read, it's not written either (Nashorn optimizes some dead writes).
+    let x = 0; 
+    if (p()) { throw {}; } // We need `p()` so this block doesn't get optimized away, for possibility of a `throw` 
+    x = 0.0; // change the type of x to double
+    r(x); // read x otherwise it's optimized away
+  } catch (e) {} // under the bug, "throw" will try to widen unwritten int x to double for here and cause a verifier error
+})()
diff --git a/test/script/basic/es6/class.js b/test/script/basic/es6/class.js
new file mode 100644
index 0000000..8897e25
--- /dev/null
+++ b/test/script/basic/es6/class.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Class declaration is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+   eval("class Foo {}");
+} catch (e) {
+   print(String(e).replace(/\\/g, "/"))
+}
diff --git a/test/script/basic/es6/class.js.EXPECTED b/test/script/basic/es6/class.js.EXPECTED
new file mode 100644
index 0000000..0d457c9
--- /dev/null
+++ b/test/script/basic/es6/class.js.EXPECTED
@@ -0,0 +1,3 @@
+java.lang.RuntimeException: test/script/basic/es6/class.js#33:3<eval>:1:0 ES6 class declarations and expressions are not yet implemented
+class Foo {}
+^
diff --git a/test/script/basic/es6/destructuring.js b/test/script/basic/es6/destructuring.js
new file mode 100644
index 0000000..d2b2a1b
--- /dev/null
+++ b/test/script/basic/es6/destructuring.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * Destructuring is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+
+function check(code) {
+   try {
+      eval(code);
+   } catch (e) {
+      print(String(e).replace(/\\/g, "/"))
+   }
+}
+
+check("var { x: y } = obj;");
+check("let { x: y } = obj;");
+check("const { x: y } = obj;");
+check("({ x: y }) = obj;");
+check("for (var { x: y } of obj) ;");
+check("for (let { x: y } of obj) ;");
+check("var { x, y } = obj;");
+check("let { x, y } = obj;");
+check("const { x, y } = obj;");
+check("({ x, y }) = obj;");
+check("for (var { x, y } of obj) ;");
+check("for (let { x, y } of obj) ;");
+check("var [a, b] = obj;");
+check("let [a, b] = obj;");
+check("const [a, b] = obj;");
+check("[a, b] = obj;");
+check("for ([a, b] of obj) ;");
+check("for (var [a, b] of obj) ;");
+check("for (let [a, b] of obj) ;");
+check("(function({ x: y }) { return x; })()");
+check("(function({ x }) { return x; })()");
+check("(function([x]) { return x; })()");
+check("for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;");
+check("for ([ arrow = () => {} ] of [[]]) ;");
+check("try { throw null;} catch({}) { }");
+check("try { throw {} } catch ({}) { }");
+check("try { throw [] } catch ([,]) { }");
+check("try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }");
+check("try { throw { a: 2, b: 3} } catch ({a, b}) { }");
+check("try { throw [null] } catch ([[x]]) { }");
+check("try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }");
+
diff --git a/test/script/basic/es6/destructuring.js.EXPECTED b/test/script/basic/es6/destructuring.js.EXPECTED
new file mode 100644
index 0000000..54ecd96
--- /dev/null
+++ b/test/script/basic/es6/destructuring.js.EXPECTED
@@ -0,0 +1,93 @@
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var { x: y } = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let { x: y } = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const { x: y } = obj;
+      ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:1 ES6 destructuring is not yet implemented
+({ x: y }) = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var { x: y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let { x: y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var { x, y } = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let { x, y } = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const { x, y } = obj;
+      ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:1 ES6 destructuring is not yet implemented
+({ x, y }) = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var { x, y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let { x, y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var [a, b] = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let [a, b] = obj;
+    ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const [a, b] = obj;
+      ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+[a, b] = obj;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for ([a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var [a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let [a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function({ x: y }) { return x; })()
+         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function({ x }) { return x; })()
+         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function([x]) { return x; })()
+         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;
+         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for ([ arrow = () => {} ] of [[]]) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:25 ES6 destructuring is not yet implemented
+try { throw null;} catch({}) { }
+                         ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw {} } catch ({}) { }
+                        ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw [] } catch ([,]) { }
+                        ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:44 ES6 destructuring is not yet implemented
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+                                            ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:35 ES6 destructuring is not yet implemented
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+                                   ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:28 ES6 destructuring is not yet implemented
+try { throw [null] } catch ([[x]]) { }
+                            ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:38 ES6 destructuring is not yet implemented
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+                                      ^
diff --git a/test/script/basic/es6/generator.js b/test/script/basic/es6/generator.js
new file mode 100644
index 0000000..88d8a0f
--- /dev/null
+++ b/test/script/basic/es6/generator.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * Generators are not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+   try {
+      eval(code);
+   } catch (e) {
+      print(String(e).replace(/\\/g, "/"))
+   }
+}
+
+check("function* func() { yield 1; }");
+check("({ * generatorMethod() { yield 1; } })");
+check("var func = function*() { yield 1; }");
diff --git a/test/script/basic/es6/generator.js.EXPECTED b/test/script/basic/es6/generator.js.EXPECTED
new file mode 100644
index 0000000..fe4b850
--- /dev/null
+++ b/test/script/basic/es6/generator.js.EXPECTED
@@ -0,0 +1,9 @@
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:17 ES6 generator is not yet implemented
+function* func() { yield 1; }
+                 ^
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:23 ES6 generator is not yet implemented
+({ * generatorMethod() { yield 1; } })
+                       ^
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:23 ES6 generator is not yet implemented
+var func = function*() { yield 1; }
+                       ^
diff --git a/test/script/basic/es6/restparam.js b/test/script/basic/es6/restparam.js
new file mode 100644
index 0000000..5db7f0b
--- /dev/null
+++ b/test/script/basic/es6/restparam.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * ES6 rest params are not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+
+function check(code) {
+   try {
+      eval(code);
+   } catch (e) {
+      print(String(e).replace(/\\/g, "/"))
+   }
+}
+
+check("function func(...args) {}");
+check("function func(x, y, ...args) {}");
+check("({ meth(...args) {} })");
+check("({ meth(x, y, ...args) {} })");
+check("({ meth(x = 0, x) {} })");
+
diff --git a/test/script/basic/es6/restparam.js.EXPECTED b/test/script/basic/es6/restparam.js.EXPECTED
new file mode 100644
index 0000000..9ccc374
--- /dev/null
+++ b/test/script/basic/es6/restparam.js.EXPECTED
@@ -0,0 +1,15 @@
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:17 ES6 function rest parameter declaration is not yet implemented
+function func(...args) {}
+                 ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:23 ES6 function rest parameter declaration is not yet implemented
+function func(x, y, ...args) {}
+                       ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:11 ES6 function rest parameter declaration is not yet implemented
+({ meth(...args) {} })
+           ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:17 ES6 function rest parameter declaration is not yet implemented
+({ meth(x, y, ...args) {} })
+                 ^
+SyntaxError: test/script/basic/es6/restparam.js#35:6<eval>:1:15 Duplicate parameter name "x"
+({ meth(x = 0, x) {} })
+               ^
diff --git a/test/script/basic/es6/spread.js b/test/script/basic/es6/spread.js
new file mode 100644
index 0000000..d90236e
--- /dev/null
+++ b/test/script/basic/es6/spread.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * ES6 spread operator is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+    try {
+        eval(code);
+    } catch (e) {
+        print(String(e).replace(/\\/g, "/"))
+    }
+}
+
+check("var x = [...args]");
+check("var x = [1, 2, ...args]");
+check("var x = [...args, 3, 5]");
+check("var r = func(...arr)");
diff --git a/test/script/basic/es6/spread.js.EXPECTED b/test/script/basic/es6/spread.js.EXPECTED
new file mode 100644
index 0000000..635f705
--- /dev/null
+++ b/test/script/basic/es6/spread.js.EXPECTED
@@ -0,0 +1,12 @@
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:9 ES6 spread operator is not yet implemented
+var x = [...args]
+         ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:15 ES6 spread operator is not yet implemented
+var x = [1, 2, ...args]
+               ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:9 ES6 spread operator is not yet implemented
+var x = [...args, 3, 5]
+         ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:13 ES6 spread operator is not yet implemented
+var r = func(...arr)
+             ^
diff --git a/test/script/basic/es6/super.js b/test/script/basic/es6/super.js
new file mode 100644
index 0000000..612d6cf
--- /dev/null
+++ b/test/script/basic/es6/super.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * ES6 super keyword is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+    try {
+        eval(code);
+    } catch (e) {
+        print(String(e).replace(/\\/g, "/"))
+    }
+}
+
+check("({ meth() { x = super.x } })");
+check("({ meth() { x = super.x() } })");
+check("({ meth() { x = super['x'] } })");
diff --git a/test/script/basic/es6/super.js.EXPECTED b/test/script/basic/es6/super.js.EXPECTED
new file mode 100644
index 0000000..2569857
--- /dev/null
+++ b/test/script/basic/es6/super.js.EXPECTED
@@ -0,0 +1,9 @@
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super.x } })
+          ^
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super.x() } })
+          ^
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super['x'] } })
+          ^
diff --git a/test/script/basic/jsadapter-ids.js b/test/script/basic/jsadapter-ids.js
index fa2f1a0..9631f4c 100644
--- a/test/script/basic/jsadapter-ids.js
+++ b/test/script/basic/jsadapter-ids.js
@@ -30,6 +30,7 @@
 
 var obj = new JSAdapter() {
     __getIds__: function() {
+        Assert.assertTrue(this === obj);
         print("__getIds__ called");
         return [ "foo", "bar" ];
     }
diff --git a/test/script/basic/jsadapter.js b/test/script/basic/jsadapter.js
index b487572..6755ffa 100644
--- a/test/script/basic/jsadapter.js
+++ b/test/script/basic/jsadapter.js
@@ -30,39 +30,81 @@
 
 var obj = new JSAdapter() {
     __get__: function(name) {
+        Assert.assertTrue(this === obj);
         print("getter called for '" + name + "'"); return name;
     },
 
     __put__: function(name, value) {
+        Assert.assertTrue(this === obj);
         print("setter called for '" + name + "' with " + value);
     },
 
     __call__: function(name, arg1, arg2) {
+        Assert.assertTrue(this === obj);
         print("method '" + name + "' called with " + arg1 + ", " + arg2);
     },
 
     __new__: function(arg1, arg2) {
+        Assert.assertTrue(this === obj);
         print("new with " + arg1 + ", " + arg2);
     },
 
     __getKeys__: function() {
+        Assert.assertTrue(this === obj);
         print("__getKeys__ called");
         return [ "foo", "bar" ];
     },
 
     __getValues__: function() {
+        Assert.assertTrue(this === obj);
         print("__getValues__ called");
         return [ "fooval", "barval" ];
     },
 
     __has__: function(name) {
+        Assert.assertTrue(this === obj);
         print("__has__ called with '" + name + "'");
         return name == "js";
     },
 
     __delete__: function(name) {
+        Assert.assertTrue(this === obj);
         print("__delete__ called with '" + name + "'");
         return true;
+    },
+
+    __preventExtensions__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__preventExtensions__ called");
+    },
+
+    __freeze__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__freeze__ called");
+
+    },
+
+    __isFrozen__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__isFrozen__ called");
+        return false;
+    },
+
+    __seal__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__seal__ called");
+    },
+
+    __isSealed__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__isSealed__ called");
+        return false;
+    },
+
+    __isExtensible__ : function() {
+        Assert.assertTrue(this === obj);
+        print("__isExtensible__ called");
+        return true;
     }
 };
 
@@ -103,3 +145,13 @@
 print(obj["js"]);
 obj["js"] = "javascript";
 print(obj["javascript"]);
+
+// call __isExtensible__, __isSealed__, __isFrozen__
+print(Object.isExtensible(obj));
+print(Object.isSealed(obj));
+print(Object.isFrozen(obj));
+
+// call __freeze__, __seal__, __preventExtensions__
+Object.freeze(obj);
+Object.seal(obj);
+Object.preventExtensions(obj);
diff --git a/test/script/basic/jsadapter.js.EXPECTED b/test/script/basic/jsadapter.js.EXPECTED
index 081048a..691cbf3 100644
--- a/test/script/basic/jsadapter.js.EXPECTED
+++ b/test/script/basic/jsadapter.js.EXPECTED
@@ -20,3 +20,12 @@
 setter called for 'js' with javascript
 getter called for 'javascript'
 javascript
+__isExtensible__ called
+true
+__isSealed__ called
+false
+__isFrozen__ called
+false
+__freeze__ called
+__seal__ called
+__preventExtensions__ called
diff --git a/test/script/basic/jsadapterlink.js b/test/script/basic/jsadapterlink.js
index ed44d61..df9148f 100644
--- a/test/script/basic/jsadapterlink.js
+++ b/test/script/basic/jsadapterlink.js
@@ -31,18 +31,21 @@
 
 var js1 = new JSAdapter() {
     __get__: function(name) {
+        Assert.assertTrue(this === js1);
         return "js1->" + name;
     }
 };
 
 var js2 = new JSAdapter() {
     __get__: function(name) {
+        Assert.assertTrue(this === js2);
         return "js2->" + name;
     }
 };
 
 var js3 = new JSAdapter() {
     __get__: function(name) {
+        Assert.assertTrue(this === js3);
         return "js3->" + name;
     }
 };
diff --git a/test/script/nosecurity/treeapi/destructuring_catch.js b/test/script/nosecurity/treeapi/destructuring_catch.js
new file mode 100644
index 0000000..ff399fe
--- /dev/null
+++ b/test/script/nosecurity/treeapi/destructuring_catch.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * Tests to check representation of ES6 catch parameter as binding pattern.
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+load(__DIR__ + "utils.js")
+
+var code = <<EOF
+
+try { throw null;} catch({}) { }
+try { throw {} } catch ({}) { }
+try { throw [] } catch ([,]) { }
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+try { throw [null] } catch ([[x]]) { }
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+
+EOF
+
+parse("destructuring_catch.js", code, "--language=es6", new (Java.extend(visitor_es6, {
+    visitCatch : function (node, obj) {
+        obj.push(convert(node))
+    }
+})))
+
diff --git a/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED b/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED
new file mode 100644
index 0000000..6389aeb
--- /dev/null
+++ b/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED
@@ -0,0 +1,399 @@
+[
+  {
+    "condition": "null",
+    "endPosition": "33",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "28",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "26",
+      "properties": []
+    },
+    "block": {
+      "endPosition": "33",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "30"
+    },
+    "startPosition": "20"
+  },
+  {
+    "condition": "null",
+    "endPosition": "65",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "60",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "58",
+      "properties": []
+    },
+    "block": {
+      "endPosition": "65",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "62"
+    },
+    "startPosition": "51"
+  },
+  {
+    "condition": "null",
+    "endPosition": "98",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "93",
+      "kind": "ARRAY_LITERAL",
+      "elements": [
+        null
+      ],
+      "startPosition": "90"
+    },
+    "block": {
+      "endPosition": "98",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "95"
+    },
+    "startPosition": "83"
+  },
+  {
+    "condition": "null",
+    "endPosition": "176",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "171",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "143",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "169",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "expression": {
+              "endPosition": "169",
+              "kind": "ARRAY_LITERAL",
+              "elements": [
+                {
+                  "endPosition": "162",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "4",
+                  "startPosition": "161"
+                },
+                {
+                  "endPosition": "165",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "5",
+                  "startPosition": "164"
+                },
+                {
+                  "endPosition": "168",
+                  "kind": "NUMBER_LITERAL",
+                  "value": "6",
+                  "startPosition": "167"
+                }
+              ],
+              "startPosition": "160"
+            },
+            "endPosition": "169",
+            "kind": "ASSIGNMENT",
+            "variable": {
+              "endPosition": "157",
+              "kind": "ARRAY_LITERAL",
+              "elements": [
+                {
+                  "endPosition": "150",
+                  "kind": "IDENTIFIER",
+                  "name": "x",
+                  "startPosition": "149"
+                },
+                {
+                  "endPosition": "153",
+                  "kind": "IDENTIFIER",
+                  "name": "y",
+                  "startPosition": "152"
+                },
+                {
+                  "endPosition": "156",
+                  "kind": "IDENTIFIER",
+                  "name": "z",
+                  "startPosition": "155"
+                }
+              ],
+              "startPosition": "148"
+            },
+            "startPosition": "148"
+          },
+          "startPosition": "145",
+          "key": {
+            "endPosition": "146",
+            "kind": "IDENTIFIER",
+            "name": "w",
+            "startPosition": "145"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "176",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "173"
+    },
+    "startPosition": "136"
+  },
+  {
+    "condition": "null",
+    "endPosition": "223",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "218",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "212",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "214",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "endPosition": "214",
+            "kind": "IDENTIFIER",
+            "name": "a",
+            "startPosition": "213"
+          },
+          "startPosition": "213",
+          "key": {
+            "endPosition": "214",
+            "kind": "IDENTIFIER",
+            "name": "a",
+            "startPosition": "213"
+          }
+        },
+        {
+          "getter": "null",
+          "endPosition": "217",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "endPosition": "217",
+            "kind": "IDENTIFIER",
+            "name": "b",
+            "startPosition": "216"
+          },
+          "startPosition": "216",
+          "key": {
+            "endPosition": "217",
+            "kind": "IDENTIFIER",
+            "name": "b",
+            "startPosition": "216"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "223",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "220"
+    },
+    "startPosition": "205"
+  },
+  {
+    "condition": "null",
+    "endPosition": "262",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "257",
+      "kind": "ARRAY_LITERAL",
+      "elements": [
+        {
+          "endPosition": "256",
+          "kind": "ARRAY_LITERAL",
+          "elements": [
+            {
+              "endPosition": "255",
+              "kind": "IDENTIFIER",
+              "name": "x",
+              "startPosition": "254"
+            }
+          ],
+          "startPosition": "253"
+        }
+      ],
+      "startPosition": "252"
+    },
+    "block": {
+      "endPosition": "262",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "259"
+    },
+    "startPosition": "245"
+  },
+  {
+    "condition": "null",
+    "endPosition": "347",
+    "kind": "CATCH",
+    "parameter": {
+      "endPosition": "342",
+      "kind": "OBJECT_LITERAL",
+      "startPosition": "301",
+      "properties": [
+        {
+          "getter": "null",
+          "endPosition": "340",
+          "kind": "PROPERTY",
+          "setter": "null",
+          "value": {
+            "expression": {
+              "endPosition": "340",
+              "kind": "OBJECT_LITERAL",
+              "startPosition": "320",
+              "properties": [
+                {
+                  "getter": "null",
+                  "endPosition": "326",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "326",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "4",
+                    "startPosition": "325"
+                  },
+                  "startPosition": "322",
+                  "key": {
+                    "endPosition": "323",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "322"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "332",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "332",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "5",
+                    "startPosition": "331"
+                  },
+                  "startPosition": "328",
+                  "key": {
+                    "endPosition": "329",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "328"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "338",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "338",
+                    "kind": "NUMBER_LITERAL",
+                    "value": "6",
+                    "startPosition": "337"
+                  },
+                  "startPosition": "334",
+                  "key": {
+                    "endPosition": "335",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "334"
+                  }
+                }
+              ]
+            },
+            "endPosition": "340",
+            "kind": "ASSIGNMENT",
+            "variable": {
+              "endPosition": "317",
+              "kind": "OBJECT_LITERAL",
+              "startPosition": "306",
+              "properties": [
+                {
+                  "getter": "null",
+                  "endPosition": "309",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "309",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "308"
+                  },
+                  "startPosition": "308",
+                  "key": {
+                    "endPosition": "309",
+                    "kind": "IDENTIFIER",
+                    "name": "x",
+                    "startPosition": "308"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "312",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "312",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "311"
+                  },
+                  "startPosition": "311",
+                  "key": {
+                    "endPosition": "312",
+                    "kind": "IDENTIFIER",
+                    "name": "y",
+                    "startPosition": "311"
+                  }
+                },
+                {
+                  "getter": "null",
+                  "endPosition": "315",
+                  "kind": "PROPERTY",
+                  "setter": "null",
+                  "value": {
+                    "endPosition": "315",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "314"
+                  },
+                  "startPosition": "314",
+                  "key": {
+                    "endPosition": "315",
+                    "kind": "IDENTIFIER",
+                    "name": "z",
+                    "startPosition": "314"
+                  }
+                }
+              ]
+            },
+            "startPosition": "306"
+          },
+          "startPosition": "303",
+          "key": {
+            "endPosition": "304",
+            "kind": "IDENTIFIER",
+            "name": "w",
+            "startPosition": "303"
+          }
+        }
+      ]
+    },
+    "block": {
+      "endPosition": "347",
+      "kind": "BLOCK",
+      "statements": [],
+      "startPosition": "344"
+    },
+    "startPosition": "294"
+  }
+]
diff --git a/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter b/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
index f3139f7..b3f34fe 100644
--- a/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
+++ b/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
@@ -1,2 +1,3 @@
 jdk.dynalink.test.UntrustedGuardingDynamicLinkerExporter
 jdk.dynalink.test.TrustedGuardingDynamicLinkerExporter
+jdk.dynalink.test.TrustedUnderscoreNameLinkerExporter
diff --git a/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java b/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
index b74f6cc..44c009f 100644
--- a/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
+++ b/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
@@ -24,14 +24,13 @@
  */
 package jdk.dynalink.beans.test;
 
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
 import static jdk.dynalink.StandardOperation.CALL;
-import static jdk.dynalink.StandardOperation.CALL_METHOD;
-import static jdk.dynalink.StandardOperation.GET_ELEMENT;
-import static jdk.dynalink.StandardOperation.GET_LENGTH;
-import static jdk.dynalink.StandardOperation.GET_METHOD;
-import static jdk.dynalink.StandardOperation.GET_PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
 import static jdk.dynalink.StandardOperation.NEW;
-import static jdk.dynalink.StandardOperation.SET_ELEMENT;
+import static jdk.dynalink.StandardOperation.SET;
 
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
@@ -39,7 +38,6 @@
 import java.lang.invoke.MethodType;
 import java.security.AccessControlException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import jdk.dynalink.CallSiteDescriptor;
@@ -78,12 +76,21 @@
     }
 
     private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) {
-        return createCallSite(publicLookup, new NamedOperation(op, name), mt);
+        return createCallSite(publicLookup, op.named(name), mt);
+    }
+
+    private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) {
+        return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class));
     }
 
     private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds");
     private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds");
 
+    private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+    private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT);
+    private static final Operation GET_METHOD = GET.withNamespace(METHOD);
+    private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT);
+
     private static final MethodHandle findThrower(final String name) {
         try {
             return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name,
@@ -209,26 +216,6 @@
     }
 
     @Test(dataProvider = "flags")
-    public void getlengthTest(final boolean publicLookup) throws Throwable {
-        final MethodType mt = MethodType.methodType(int.class, Object.class);
-        final CallSite cs = createCallSite(publicLookup, GET_LENGTH, mt);
-
-        final int[] arr = {23, 42};
-        Assert.assertEquals((int) cs.getTarget().invoke((Object) arr), 2);
-        Assert.assertEquals((int) cs.getTarget().invoke(Collections.EMPTY_LIST), 0);
-
-        final List<String> list = new ArrayList<>();
-        list.add("hello");
-        list.add("world");
-        list.add("dynalink");
-        Assert.assertEquals((int) cs.getTarget().invoke(list), 3);
-        list.add("nashorn");
-        Assert.assertEquals((int) cs.getTarget().invoke(list), 4);
-        list.clear();
-        Assert.assertEquals((int) cs.getTarget().invoke(list), 0);
-    }
-
-    @Test(dataProvider = "flags")
     public void getElementTest(final boolean publicLookup) throws Throwable {
         final MethodType mt = MethodType.methodType(int.class, Object.class, int.class);
         final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt);
@@ -364,8 +351,7 @@
 
     @Test(dataProvider = "flags")
     public void instanceMethodCallTest(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(Object.class, Object.class);
-        final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getClass", mt);
+        final CallSite cs = createGetMethodCallSite(publicLookup, "getClass");
         final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class);
         final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
 
@@ -389,23 +375,8 @@
     }
 
     @Test(dataProvider = "flags")
-    public void instanceMethodCallTest2(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(Class.class, Object.class);
-        final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getClass", mt);
-        Class clz = null;
-        try {
-            clz = (Class) cs.getTarget().invoke(new Date());
-        } catch (final Throwable th) {
-            throw new RuntimeException(th);
-        }
-
-        Assert.assertEquals(clz, Date.class);
-    }
-
-    @Test(dataProvider = "flags")
     public void staticMethodCallTest(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(Object.class, StaticClass.class);
-        final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getProperty", mt);
+        final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty");
         final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class);
         final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
 
@@ -428,28 +399,15 @@
         Assert.assertEquals(str, System.getProperty("os.name"));
     }
 
-    @Test(dataProvider = "flags")
-    public void staticMethodCallTest2(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
-        final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
-
-        String str = null;
-        try {
-            str = (String) cs.getTarget().invoke(StaticClass.forClass(System.class), "os.name");
-        } catch (final Throwable th) {
-            throw new RuntimeException(th);
-        }
-        Assert.assertEquals(str, System.getProperty("os.name"));
-    }
-
     // try calling System.getenv and expect security exception
     @Test(dataProvider = "flags")
     public void systemGetenvTest(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(Object.class, Object.class);
-        final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getenv", mt);
+        final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv");
+        final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class));
 
         try {
-            cs.getTarget().invoke(StaticClass.forClass(System.class));
+            final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+            cs2.getTarget().invoke(method, StaticClass.forClass(System.class));
             throw new RuntimeException("should not reach here in any case!");
         } catch (final Throwable th) {
             Assert.assertTrue(th instanceof SecurityException);
@@ -459,11 +417,12 @@
     // try getting a specific sensitive System property and expect security exception
     @Test(dataProvider = "flags")
     public void systemGetPropertyTest(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
-        final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
+        final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty");
+        final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class));
 
         try {
-            cs.getTarget().invoke(StaticClass.forClass(System.class), "java.home");
+            final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+            cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home");
             throw new RuntimeException("should not reach here in any case!");
         } catch (final Throwable th) {
             Assert.assertTrue(th instanceof SecurityException);
@@ -473,11 +432,12 @@
     // check a @CallerSensitive API and expect appropriate access check exception
     @Test(dataProvider = "flags")
     public void systemLoadLibraryTest(final boolean publicLookup) {
-        final MethodType mt = MethodType.methodType(void.class, Object.class, String.class);
-        final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "loadLibrary", mt);
+        final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary");
+        final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class));
 
         try {
-            cs.getTarget().invoke(StaticClass.forClass(System.class), "foo");
+            final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+            cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo");
             throw new RuntimeException("should not reach here in any case!");
         } catch (final Throwable th) {
             if (publicLookup) {
diff --git a/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java b/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
index 8ef147f..c5d2862 100644
--- a/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
+++ b/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
@@ -24,12 +24,12 @@
  */
 package jdk.dynalink.beans.test;
 
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
 import static jdk.dynalink.StandardOperation.CALL;
-import static jdk.dynalink.StandardOperation.GET_ELEMENT;
-import static jdk.dynalink.StandardOperation.GET_METHOD;
-import static jdk.dynalink.StandardOperation.GET_PROPERTY;
-import static jdk.dynalink.StandardOperation.SET_ELEMENT;
-import static jdk.dynalink.StandardOperation.SET_PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
 
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
@@ -42,12 +42,11 @@
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
 import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Namespace;
+import jdk.dynalink.NamespaceOperation;
 import jdk.dynalink.NoSuchDynamicMethodException;
 import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
 import jdk.dynalink.support.SimpleRelinkableCallSite;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -67,32 +66,32 @@
 
     @Test
     public static void testPublicFieldPropertyUnnamedGetter() {
-        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
+        testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
     }
 
     @Test
     public static void testPublicFieldPropertyNamedGetter() {
-        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(named("answer", op), new Bean1())));
+        testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op.named("answer"), new Bean1())));
     }
 
     @Test
     public static void testGetterPropertyUnnamedGetter() {
-        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
+        testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
     }
 
     @Test
     public static void testGetterPropertyNamedGetter() {
-        testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(named("name", op), new Bean1())));
+        testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op.named("name"), new Bean1())));
     }
 
     @Test
     public static void testMethodUnnamedGetter() {
-        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
+        testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
     }
 
     @Test
     public static void testMethodNamedGetter() {
-        testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(named("someMethod", op), new Bean1()), new Bean1(), "bar")));
+        testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op.named("someMethod"), new Bean1()), new Bean1(), "bar")));
     }
 
     private static final Map<String, String> MAP1 = new HashMap<>();
@@ -102,12 +101,12 @@
 
     @Test
     public static void testElementUnnamedGetter() {
-        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
+        testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
     }
 
     @Test
     public static void testElementNamedGetter() {
-        testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(named("foo", op), MAP1)));
+        testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op.named("foo"), MAP1)));
     }
 
     public static class Bean2 {
@@ -121,7 +120,7 @@
 
     @Test
     public static void testUnnamedFieldSetter() {
-        testSetterPermutations(SET_PROPERTY, (op) -> {
+        testSetterPermutations(PROPERTY, (op) -> {
             final Bean2 bean2 = new Bean2();
             call(op, bean2, "answer", 12);
             Assert.assertEquals(bean2.answer, 12);
@@ -130,16 +129,16 @@
 
     @Test
     public static void testNamedFieldSetter() {
-        testSetterPermutations(SET_PROPERTY, (op) -> {
+        testSetterPermutations(PROPERTY, (op) -> {
             final Bean2 bean2 = new Bean2();
-            call(named("answer", op), bean2, 14);
+            call(op.named("answer"), bean2, 14);
             Assert.assertEquals(bean2.answer, 14);
         });
     }
 
     @Test
     public static void testUnnamedPropertySetter() {
-        testSetterPermutations(SET_PROPERTY, (op) -> {
+        testSetterPermutations(PROPERTY, (op) -> {
             final Bean2 bean2 = new Bean2();
             call(op, bean2, "name", "boo");
             Assert.assertEquals(bean2.name, "boo");
@@ -148,14 +147,14 @@
 
     @Test
     public static void testNamedPropertySetter() {
-        testSetterPermutations(SET_PROPERTY, (op) -> {
+        testSetterPermutations(PROPERTY, (op) -> {
             final Bean2 bean2 = new Bean2();
-            call(named("name", op), bean2, "blah");
+            call(op.named("name"), bean2, "blah");
             Assert.assertEquals(bean2.name, "blah");
         });
     }
 
-    private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*GET_ELEMENT.*GET_PROPERTY.*");
+    private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*ELEMENT.*PROPERTY.*");
 
     @Test
     public static void testUnnamedElementAndPropertyGetter() {
@@ -168,10 +167,10 @@
     public static void testNamedElementAndPropertyGetter() {
         final Map<String, Object> map = new HashMap<>();
         map.put("empty", true);
-        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(named("empty", op), map)));
+        testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op.named("empty"), map)));
     }
 
-    private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*GET_PROPERTY.*GET_ELEMENT.*");
+    private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*PROPERTY.*ELEMENT.*");
 
     @Test
     public static void testUnnamedPropertyAndElementGetter() {
@@ -184,7 +183,7 @@
     public static void testNamedPropertyAndElementGetter() {
         final Map<String, Object> map = new HashMap<>();
         map.put("empty", true);
-        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(named("empty", op), map)));
+        testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op.named("empty"), map)));
     }
 
     public static class MapWithProperty extends HashMap<String, Object> {
@@ -200,24 +199,24 @@
         final MapWithProperty map = new MapWithProperty();
         map.put("name", "element");
 
-        call(ops(SET_PROPERTY, SET_ELEMENT), map, "name", "property");
+        call(SET.withNamespaces(PROPERTY, ELEMENT), map, "name", "property");
         Assert.assertEquals("property", map.name);
         Assert.assertEquals("element", map.get("name"));
 
-        call(ops(SET_ELEMENT, SET_PROPERTY), map, "name", "element2");
+        call(SET.withNamespaces(ELEMENT, PROPERTY), map, "name", "element2");
         Assert.assertEquals("property", map.name);
         Assert.assertEquals("element2", map.get("name"));
     }
 
     @Test
     public static void testMissingMembersAtLinkTime() {
-        testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object())));
-        testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object(), "newValue")));
+        testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object())));
+        testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object(), "newValue")));
     }
 
     @Test
     public static void testMissingMembersAtRunTime() {
-        call(GET_ELEMENT, new ArrayList<>(), "foo");
+        call(GET.withNamespace(ELEMENT), new ArrayList<>(), "foo");
         Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> {
             testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));});
             // No assertion for the setter; we just expect it to silently succeed
@@ -233,59 +232,59 @@
         }
     }
 
-    private static Operation[] GETTER_PERMUTATIONS = new Operation[] {
-        GET_PROPERTY,
-        GET_METHOD,
-        GET_ELEMENT,
-        ops(GET_PROPERTY, GET_ELEMENT),
-        ops(GET_PROPERTY, GET_METHOD),
-        ops(GET_ELEMENT,  GET_PROPERTY),
-        ops(GET_ELEMENT,  GET_METHOD),
-        ops(GET_METHOD,   GET_PROPERTY),
-        ops(GET_METHOD,   GET_ELEMENT),
-        ops(GET_PROPERTY, GET_ELEMENT,  GET_METHOD),
-        ops(GET_PROPERTY, GET_METHOD,   GET_ELEMENT),
-        ops(GET_ELEMENT,  GET_PROPERTY, GET_METHOD),
-        ops(GET_ELEMENT,  GET_METHOD,   GET_PROPERTY),
-        ops(GET_METHOD,   GET_PROPERTY, GET_ELEMENT),
-        ops(GET_METHOD,   GET_ELEMENT,  GET_PROPERTY),
+    private static NamespaceOperation[] GETTER_PERMUTATIONS = new NamespaceOperation[] {
+        GET.withNamespaces(PROPERTY),
+        GET.withNamespaces(METHOD),
+        GET.withNamespaces(ELEMENT),
+        GET.withNamespaces(PROPERTY, ELEMENT),
+        GET.withNamespaces(PROPERTY, METHOD),
+        GET.withNamespaces(ELEMENT,  PROPERTY),
+        GET.withNamespaces(ELEMENT,  METHOD),
+        GET.withNamespaces(METHOD,   PROPERTY),
+        GET.withNamespaces(METHOD,   ELEMENT),
+        GET.withNamespaces(PROPERTY, ELEMENT,  METHOD),
+        GET.withNamespaces(PROPERTY, METHOD,   ELEMENT),
+        GET.withNamespaces(ELEMENT,  PROPERTY, METHOD),
+        GET.withNamespaces(ELEMENT,  METHOD,   PROPERTY),
+        GET.withNamespaces(METHOD,   PROPERTY, ELEMENT),
+        GET.withNamespaces(METHOD,   ELEMENT,  PROPERTY)
     };
 
-    private static Operation[] SETTER_PERMUTATIONS = new Operation[] {
-        SET_PROPERTY,
-        SET_ELEMENT,
-        ops(SET_PROPERTY, SET_ELEMENT),
-        ops(SET_ELEMENT,  SET_PROPERTY)
+    private static NamespaceOperation[] SETTER_PERMUTATIONS = new NamespaceOperation[] {
+        SET.withNamespaces(PROPERTY),
+        SET.withNamespaces(ELEMENT),
+        SET.withNamespaces(PROPERTY, ELEMENT),
+        SET.withNamespaces(ELEMENT, PROPERTY)
     };
 
-    private static void testPermutations(final Operation[] ops, final StandardOperation requiredOp, final int expectedCount, final Consumer<Operation> test) {
-        testPermutationsWithFilter(ops, (op)->CompositeOperation.contains(op, requiredOp), expectedCount, test);
+    private static void testPermutations(final NamespaceOperation[] ops, final Operation requiredOp, final Namespace requiredNamespace, final int expectedCount, final Consumer<NamespaceOperation> test) {
+        testPermutationsWithFilter(ops, (op)->NamespaceOperation.contains(op, requiredOp, requiredNamespace), expectedCount, test);
     }
 
-    private static void testPermutations(final Operation[] ops, final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
+    private static void testPermutations(final NamespaceOperation[] ops, final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
         testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
     }
 
-    private static void testPermutations(final Operation[] ops, final Consumer<Operation> test) {
+    private static void testPermutations(final NamespaceOperation[] ops, final Consumer<NamespaceOperation> test) {
         testPermutationsWithFilter(ops, (op)->true, ops.length, test);
     }
 
-    private static void testPermutationsWithFilter(final Operation[] ops, final Predicate<Operation> filter, final int expectedCount, final Consumer<Operation> test) {
+    private static void testPermutationsWithFilter(final NamespaceOperation[] ops, final Predicate<NamespaceOperation> filter, final int expectedCount, final Consumer<NamespaceOperation> test) {
         final int[] counter = new int[1];
         Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
         Assert.assertEquals(counter[0], expectedCount);
     }
 
-    private static void testGetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
-        testPermutations(GETTER_PERMUTATIONS, requiredOp, 11, test);
+    private static void testGetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
+        testPermutations(GETTER_PERMUTATIONS, GET, requiredNamespace, 11, test);
     }
 
-    private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
+    private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
         testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test);
     }
 
-    private static void testSetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
-        testPermutations(SETTER_PERMUTATIONS, requiredOp, 3, test);
+    private static void testSetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
+        testPermutations(SETTER_PERMUTATIONS, SET, requiredNamespace, 3, test);
     }
 
     private static Object call(final Operation op, final Object... args) {
@@ -305,14 +304,6 @@
         return call(CALL, args);
     }
 
-    private static Operation named(final Object name, final Operation... ops) {
-        return new NamedOperation(ops(ops), name);
-    }
-
-    private static Operation ops(final Operation... ops) {
-        return ops.length == 1 ? ops[0] : new CompositeOperation(ops);
-    }
-
     private static MethodType t(final int argCount) {
         return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class));
     }
diff --git a/test/src/jdk/dynalink/support/test/CallSiteTest.java b/test/src/jdk/dynalink/support/test/CallSiteTest.java
index d33aa0a..2649a99 100644
--- a/test/src/jdk/dynalink/support/test/CallSiteTest.java
+++ b/test/src/jdk/dynalink/support/test/CallSiteTest.java
@@ -25,6 +25,9 @@
 
 package jdk.dynalink.support.test;
 
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -33,14 +36,15 @@
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.DynamicLinker;
 import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
+import jdk.dynalink.Operation;
 import jdk.dynalink.linker.GuardedInvocation;
 import jdk.dynalink.support.SimpleRelinkableCallSite;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class CallSiteTest {
+    private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+
     @Test
     public void testInitialize() {
         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
@@ -48,7 +52,7 @@
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
         final boolean[] initializeCalled = { Boolean.FALSE };
         linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
-            MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "DO_NOT_CARE"), mt)) {
+            MethodHandles.publicLookup(), GET_PROPERTY.named("DO_NOT_CARE"), mt)) {
                 @Override
                 public void initialize(final MethodHandle relinkAndInvoke) {
                     initializeCalled[0] = Boolean.TRUE;
@@ -66,7 +70,7 @@
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
         final boolean[] relinkCalled = { Boolean.FALSE };
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
-            MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "class"), mt)) {
+            MethodHandles.publicLookup(), GET_PROPERTY.named("class"), mt)) {
                 @Override
                 public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
                     relinkCalled[0] = Boolean.TRUE;
@@ -90,7 +94,7 @@
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
         final boolean[] resetAndRelinkCalled = { Boolean.FALSE };
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
-            MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "length"), mt)) {
+            MethodHandles.publicLookup(), GET_PROPERTY.named("length"), mt)) {
                 @Override
                 public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
                     resetAndRelinkCalled[0] = Boolean.TRUE;
diff --git a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
index 2addefb..4199da2 100644
--- a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
+++ b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
@@ -24,6 +24,9 @@
  */
 package jdk.dynalink.test;
 
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+
 import java.lang.invoke.CallSite;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -35,9 +38,9 @@
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.DynamicLinker;
 import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
 import jdk.dynalink.NoSuchDynamicMethodException;
 import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
 import jdk.dynalink.StandardOperation;
 import jdk.dynalink.beans.StaticClass;
 import jdk.dynalink.linker.GuardedInvocation;
@@ -52,6 +55,8 @@
 @SuppressWarnings("javadoc")
 public class DynamicLinkerFactoryTest {
 
+    private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+
     private static DynamicLinkerFactory newDynamicLinkerFactory(final boolean resetClassLoader) {
         final DynamicLinkerFactory factory = new DynamicLinkerFactory();
         if (resetClassLoader) {
@@ -190,7 +195,7 @@
         final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
         final DynamicLinker linker = factory.createLinker();
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
-                MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
+                MethodHandles.publicLookup(), GET_PROPERTY, mt)));
         Assert.assertFalse(reachedPrelinkTransformer[0]);
         Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
         Assert.assertTrue(reachedPrelinkTransformer[0]);
@@ -209,7 +214,7 @@
         final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
         final DynamicLinker linker = factory.createLinker();
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
-                MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
+                MethodHandles.publicLookup(), GET_PROPERTY, mt)));
         Assert.assertFalse(reachedInternalObjectsFilter[0]);
         Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
         Assert.assertTrue(reachedInternalObjectsFilter[0]);
@@ -252,7 +257,7 @@
 
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
         final CallSiteDescriptor testDescriptor = new CallSiteDescriptor(MethodHandles.publicLookup(),
-                new NamedOperation(StandardOperation.GET_METHOD, methodName), mt);
+                GET.withNamespace(StandardNamespace.METHOD).named(methodName), mt);
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(testDescriptor));
 
         TrustedGuardingDynamicLinkerExporter.enable();
@@ -274,7 +279,7 @@
         final DynamicLinker linker = factory.createLinker();
 
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
-        final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+        final Operation op = GET_PROPERTY.named("foo");
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
                 MethodHandles.publicLookup(), op, mt)));
         final boolean[] reachedGetMember = new boolean[1];
@@ -306,7 +311,7 @@
         // check that the nashorn exported linker can be used for ScriptObjectMirror
         final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
         final MethodType mt = MethodType.methodType(Object.class, Object.class);
-        final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+        final Operation op = GET_PROPERTY.named("foo");
         final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
                 MethodHandles.publicLookup(), op, mt)));
         Object value = null;
diff --git a/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java b/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
index 8e2b03b..00b56ba 100644
--- a/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
+++ b/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
@@ -24,20 +24,21 @@
  */
 package jdk.dynalink.test;
 
-import static jdk.dynalink.StandardOperation.CALL_METHOD;
-
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import jdk.dynalink.CallSiteDescriptor;
 import jdk.dynalink.DynamicLinker;
 import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
+import jdk.dynalink.StandardOperation;
 import jdk.dynalink.linker.GuardingDynamicLinker;
 import jdk.dynalink.support.SimpleRelinkableCallSite;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class LinkedCallSiteLocationTest {
+    private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD);
     @Test
     public void testLinkedCallSiteLocation() throws Throwable {
         final StackTraceElement[] lastLinked = new StackTraceElement[1];
@@ -51,7 +52,7 @@
         final SimpleRelinkableCallSite callSite = new SimpleRelinkableCallSite(
                 new CallSiteDescriptor(
                         MethodHandles.lookup(),
-                        new NamedOperation(CALL_METHOD, "foo"),
+                        GET_METHOD.named("foo"),
                         MethodType.methodType(void.class, Object.class)));
         linker.link(callSite);
 
diff --git a/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java b/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java
new file mode 100644
index 0000000..9b21da5
--- /dev/null
+++ b/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+package jdk.dynalink.test;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
+import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
+import jdk.dynalink.StandardOperation;
+import jdk.dynalink.linker.GuardedInvocation;
+import jdk.dynalink.linker.GuardingDynamicLinker;
+import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
+import jdk.dynalink.linker.LinkRequest;
+import jdk.dynalink.linker.LinkerServices;
+import jdk.dynalink.linker.support.SimpleLinkRequest;
+
+/**
+ * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276).
+ * This linker translater underscore_separated method names to CamelCase names
+ * used in Java APIs.
+ */
+public final class TrustedUnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter {
+    private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)");
+
+    // translate underscore_separated name as a CamelCase name
+    private static String translateToCamelCase(final String name) {
+        final Matcher m = UNDERSCORE_NAME.matcher(name);
+        final StringBuilder buf = new StringBuilder();
+        while (m.find()) {
+            m.appendReplacement(buf, m.group(1).toUpperCase());
+        }
+        m.appendTail(buf);
+        return buf.toString();
+    }
+
+    @Override
+    public List<GuardingDynamicLinker> get() {
+        final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
+        linkers.add(new GuardingDynamicLinker() {
+            @Override
+            public GuardedInvocation getGuardedInvocation(final LinkRequest request,
+                final LinkerServices linkerServices) throws Exception {
+                final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+                final Operation op = desc.getOperation();
+                final Object name = NamedOperation.getName(op);
+                final Operation namespaceOp = NamedOperation.getBaseOperation(op);
+                // is this a named GET_METHOD?
+                final boolean isGetMethod =
+                        NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
+                        && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
+                if (isGetMethod && name instanceof String) {
+                    final String str = (String)name;
+                    if (str.indexOf('_') == -1) {
+                        return null;
+                    }
+
+                    final String nameStr = translateToCamelCase(str);
+                    // create a new call descriptor to use translated name
+                    final CallSiteDescriptor newDesc = AccessController.doPrivileged(
+                        new PrivilegedAction<CallSiteDescriptor>() {
+                            @Override
+                            public CallSiteDescriptor run() {
+                                return desc.changeOperation(((NamedOperation)op).changeName(nameStr));
+                            }
+                        });
+                    // create a new Link request to link the call site with translated name
+                    final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
+                    // return guarded invocation linking the translated request
+                    return linkerServices.getGuardedInvocation(newRequest);
+                }
+
+                return null;
+            }
+        });
+        return linkers;
+    }
+}
diff --git a/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java b/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
index 45d1264..56ed51e 100644
--- a/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
+++ b/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
@@ -104,11 +104,11 @@
     @Test
     public void testVarArgs() throws ScriptException {
         // Sole NativeArray in vararg position becomes vararg array itself
-        runTest("assertVarArg_42_17", "[42, 17]");
+        runTest("assertVarArgWith42And17", "[42, 17]");
         // NativeArray in vararg position becomes an argument if there are more arguments
-        runTest("assertVarArg_array_17", "[42], 18");
+        runTest("assertVarArgArray7", "[42], 18");
         // Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't
-        runTest("assertVarArg_function", "function() { return 'Hello' }");
+        runTest("assertVarArgFunction", "function() { return 'Hello' }");
     }
 
     private static void runTest(final String testMethodName, final String argument) throws ScriptException {
@@ -209,20 +209,20 @@
         assertEquals(Arrays.asList("apple", "orange"), array[1]);
     }
 
-    public static void assertVarArg_42_17(final Object... args) {
+    public static void assertVarArgWith42And17(final Object... args) {
         assertEquals(2, args.length);
         assertEquals(42, ((Number)args[0]).intValue());
         assertEquals(17, ((Number)args[1]).intValue());
     }
 
-    public static void assertVarArg_array_17(final Object... args) throws ScriptException {
+    public static void assertVarArgArray7(final Object... args) throws ScriptException {
         assertEquals(2, args.length);
         e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]);
         assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42"));
         assertEquals(18, ((Number)args[1]).intValue());
     }
 
-    public static void assertVarArg_function(final Object... args) throws ScriptException {
+    public static void assertVarArgFunction(final Object... args) throws ScriptException {
         assertEquals(1, args.length);
         e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]);
         assertEquals("Hello", e.eval("fn()"));
diff --git a/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java b/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java
new file mode 100644
index 0000000..357b7c4
--- /dev/null
+++ b/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.test;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @bug 8169050
+ * @summary underscore_linker.js sample fails after dynalink changes for JDK-8168005
+ */
+public class JDK_8169050_Test {
+    private ScriptEngine engine;
+
+    @BeforeClass
+    public void setupTest() {
+        engine = new ScriptEngineManager().getEngineByName("js");
+    }
+
+    @Test
+    public void testUndersoreName() throws ScriptException {
+        engine.eval("var S = java.util.stream.Stream, v = 0;");
+        // The underscore name 'for_each' exercises pluggable dynalink linker
+        engine.eval("S.of(4, 5, 9).for_each(function(x) { v += x })");
+        assertEquals(18, ((Number)engine.get("v")).intValue());
+    }
+}