NashornBeansLinker.java revision 953:221a84ef44c0
1279264Sdelphij/*
2110010Smarkm * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3110010Smarkm * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4160819Ssimon *
5110010Smarkm * This code is free software; you can redistribute it and/or modify it
6110010Smarkm * under the terms of the GNU General Public License version 2 only, as
7110010Smarkm * published by the Free Software Foundation.  Oracle designates this
8110010Smarkm * particular file as subject to the "Classpath" exception as provided
9110010Smarkm * by Oracle in the LICENSE file that accompanied this code.
10110010Smarkm *
11110010Smarkm * This code is distributed in the hope that it will be useful, but WITHOUT
12110010Smarkm * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13110010Smarkm * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14110010Smarkm * version 2 for more details (a copy is included in the LICENSE file that
15110010Smarkm * accompanied this code).
16110010Smarkm *
17110010Smarkm * You should have received a copy of the GNU General Public License version
18110010Smarkm * 2 along with this work; if not, write to the Free Software Foundation,
19110010Smarkm * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20215698Ssimon *
21215698Ssimon * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22215698Ssimon * or visit www.oracle.com if you need additional information or have any
23215698Ssimon * questions.
24215698Ssimon */
25110010Smarkm
26110010Smarkmpackage jdk.nashorn.internal.runtime.linker;
27110010Smarkm
28110010Smarkmimport java.lang.invoke.MethodHandle;
29110010Smarkmimport java.lang.invoke.MethodHandles;
30110010Smarkmimport java.lang.invoke.MethodType;
31110010Smarkmimport jdk.internal.dynalink.beans.BeansLinker;
32110010Smarkmimport jdk.internal.dynalink.linker.ConversionComparator.Comparison;
33110010Smarkmimport jdk.internal.dynalink.linker.GuardedInvocation;
34110010Smarkmimport jdk.internal.dynalink.linker.GuardingDynamicLinker;
35110010Smarkmimport jdk.internal.dynalink.linker.LinkRequest;
36110010Smarkmimport jdk.internal.dynalink.linker.LinkerServices;
37110010Smarkmimport jdk.internal.dynalink.support.Lookup;
38110010Smarkmimport jdk.nashorn.internal.runtime.ConsString;
39110010Smarkm
40110010Smarkm/**
41279264Sdelphij * This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
42279264Sdelphij * {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
43110010Smarkm * observable (currently only ConsString) to Java APIs, but rather that we flatten it into a String. We can't just add
44110010Smarkm * this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
45215698Ssimon * the target method handle parameter signature is {@code Object}.
46215698Ssimon */
47215698Ssimonpublic class NashornBeansLinker implements GuardingDynamicLinker {
48215698Ssimon    private static final MethodHandle EXPORT_ARGUMENT = new Lookup(MethodHandles.lookup()).findOwnStatic("exportArgument", Object.class, Object.class);
49160819Ssimon
50215698Ssimon    private final BeansLinker beansLinker = new BeansLinker();
51160819Ssimon
52160819Ssimon    @Override
53279264Sdelphij    public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
54279264Sdelphij        return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
55279264Sdelphij    }
56110010Smarkm
57279264Sdelphij    /**
58279264Sdelphij     * Delegates to the specified linker but injects its linker services wrapper so that it will apply all special
59279264Sdelphij     * conversions that this class does.
60279264Sdelphij     * @param delegateLinker the linker to which the actual work is delegated to.
61279264Sdelphij     * @param linkRequest the delegated link request
62279264Sdelphij     * @param linkerServices the original link services that will be augmented with special conversions
63215698Ssimon     * @return the guarded invocation from the delegate, possibly augmented with special conversions
64279264Sdelphij     * @throws Exception if the delegate throws an exception
65279264Sdelphij     */
66279264Sdelphij    public static GuardedInvocation getGuardedInvocation(final GuardingDynamicLinker delegateLinker, final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
67279264Sdelphij        return delegateLinker.getGuardedInvocation(linkRequest, new NashornBeansLinkerServices(linkerServices));
68279264Sdelphij    }
69215698Ssimon
70279264Sdelphij    static Object exportArgument(final Object arg) {
71110010Smarkm        return arg instanceof ConsString ? arg.toString() : arg;
72110010Smarkm    }
73110010Smarkm
74110010Smarkm    private static class NashornBeansLinkerServices implements LinkerServices {
75110010Smarkm        private final LinkerServices linkerServices;
76110010Smarkm
77110010Smarkm        NashornBeansLinkerServices(final LinkerServices linkerServices) {
78110010Smarkm            this.linkerServices = linkerServices;
79110010Smarkm        }
80110010Smarkm
81110010Smarkm        @Override
82110010Smarkm        public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
83110010Smarkm            final MethodHandle typed = linkerServices.asType(handle, fromType);
84110010Smarkm
85110010Smarkm            final MethodType handleType = handle.type();
86110010Smarkm            final int paramCount = handleType.parameterCount();
87110010Smarkm            assert fromType.parameterCount() == handleType.parameterCount();
88110010Smarkm
89110010Smarkm            MethodHandle[] filters = null;
90110010Smarkm            for(int i = 0; i < paramCount; ++i) {
91110010Smarkm                if(shouldConvert(handleType.parameterType(i), fromType.parameterType(i))) {
92110010Smarkm                    if(filters == null) {
93110010Smarkm                        filters = new MethodHandle[paramCount];
94110010Smarkm                    }
95110010Smarkm                    filters[i] = EXPORT_ARGUMENT;
96110010Smarkm                }
97110010Smarkm            }
98110010Smarkm
99110010Smarkm            return filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
100110010Smarkm        }
101110010Smarkm
102110010Smarkm        @Override
103110010Smarkm        public MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
104110010Smarkm            return Implementation.asTypeLosslessReturn(this, handle, fromType);
105110010Smarkm        }
106110010Smarkm
107110010Smarkm        private static boolean shouldConvert(final Class<?> handleType, final Class<?> fromType) {
108110010Smarkm            return handleType == Object.class && fromType == Object.class;
109110010Smarkm        }
110110010Smarkm
111110010Smarkm        @Override
112110010Smarkm        public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
113110010Smarkm            return linkerServices.getTypeConverter(sourceType, targetType);
114110010Smarkm        }
115110010Smarkm
116110010Smarkm        @Override
117110010Smarkm        public boolean canConvert(final Class<?> from, final Class<?> to) {
118110010Smarkm            return linkerServices.canConvert(from, to);
119110010Smarkm        }
120110010Smarkm
121110010Smarkm        @Override
122110010Smarkm        public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
123110010Smarkm            return linkerServices.getGuardedInvocation(linkRequest);
124110010Smarkm        }
125110010Smarkm
126110010Smarkm        @Override
127110010Smarkm        public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
128110010Smarkm            return linkerServices.compareConversion(sourceType, targetType1, targetType2);
129110010Smarkm        }
130110010Smarkm    }
131110010Smarkm}
132110010Smarkm