changeset 1806:7caf1f762f1d

8168005: Introduce namespaces for GET, SET Dynalink operations Reviewed-by: hannesw, sundar
author attila
date Tue, 01 Nov 2016 15:31:44 +0100
parents 96f47313aae7
children b4e57ead3fae
files samples/dynalink/ArrayStreamLinkerExporter.java samples/dynalink/BufferIndexingLinkerExporter.java samples/dynalink/DOMLinkerExporter.java samples/dynalink/MissingMethodLinkerExporter.java samples/dynalink/UnderscoreNameLinkerExporter.java src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java test/src/jdk/dynalink/beans/test/BeanLinkerTest.java test/src/jdk/dynalink/beans/test/BeansLinkerTest.java test/src/jdk/dynalink/support/test/CallSiteTest.java test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
diffstat 41 files changed, 1204 insertions(+), 1013 deletions(-) [+]
line wrap: on
line diff
--- a/samples/dynalink/ArrayStreamLinkerExporter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/samples/dynalink/ArrayStreamLinkerExporter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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));
--- a/samples/dynalink/BufferIndexingLinkerExporter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/samples/dynalink/BufferIndexingLinkerExporter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/samples/dynalink/DOMLinkerExporter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/samples/dynalink/DOMLinkerExporter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
 
--- a/samples/dynalink/MissingMethodLinkerExporter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/samples/dynalink/MissingMethodLinkerExporter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
 
--- a/samples/dynalink/UnderscoreNameLinkerExporter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/samples/dynalink/UnderscoreNameLinkerExporter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
                 }
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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());
+        }
+    }
 }
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java	Fri Oct 28 16:52:20 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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));
-    }
-}
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
+    }
+}
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
+    }
+}
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
     }
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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.");
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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)}.
      *
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
         }
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
@@ -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
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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
             }
         }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
             }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
         }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
     }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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,
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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) {
+                // Obtain the method
+                final CallSiteDescriptor getMethodDesc = new CallSiteDescriptor(
+                        NashornCallSiteDescriptor.getLookupInternal(desc),
+                        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();
-                // drop callee (Undefined ScriptFunction) and change the request to be CALL_METHOD:<name>
-                final CallSiteDescriptor newDesc = 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()),
+
+                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);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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.
-     * @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.
+     * 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 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 boolean isMethodFirstOperation(final CallSiteDescriptor desc) {
+        return findFirstStandardNamespace(desc) == StandardNamespace.METHOD;
     }
 
     /**
-     * Returns true if the passed call site descriptor's operation contains (or
-     * is) the specified standard operation.
+     * 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 the base operation in this call site descriptor.
+     */
+    public static Operation getBaseOperation(final CallSiteDescriptor desc) {
+        return NamespaceOperation.getBaseOperation(NamedOperation.getBaseOperation(desc.getOperation()));
+    }
+
+    /**
+     * 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);
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
                     }
                 }
--- a/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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) {
--- a/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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));
     }
--- a/test/src/jdk/dynalink/support/test/CallSiteTest.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/test/src/jdk/dynalink/support/test/CallSiteTest.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java	Fri Oct 28 16:52:20 2016 +0200
+++ b/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java	Tue Nov 01 15:31:44 2016 +0100
@@ -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);