
org.mozilla.javascript.optimizer.ConstAwareLinker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically
embedded into Java applications to provide scripting to end users.
The newest version!
package org.mozilla.javascript.optimizer;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.LinkerServices;
import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.dynalink.linker.support.Guards;
import org.mozilla.javascript.NativeWith;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.ScriptableObject;
/**
* This linker optimizes accesses to constants, either as object properties or in the current scope.
* These constants must be truly constants, which means neither "writable" nor "configurable," which
* pretty much means that they were declared with the "const" keyword. In those cases, it will
* replace the entire property lookup with code that directly returns the constant value, which is
* much faster.
*/
@SuppressWarnings("AndroidJdkLibsChecker")
class ConstAwareLinker implements TypeBasedGuardingDynamicLinker {
@Override
public boolean canLinkType(Class> type) {
return ScriptableObject.class.isAssignableFrom(type)
|| NativeWith.class.isAssignableFrom(type);
}
@Override
public GuardedInvocation getGuardedInvocation(LinkRequest req, LinkerServices svc) {
if (req.isCallSiteUnstable()) {
return null;
}
ParsedOperation op = new ParsedOperation(req.getCallSiteDescriptor().getOperation());
Object target = req.getReceiver();
if ((op.isNamespace(RhinoNamespace.NAME) && op.isOperation(StandardOperation.GET))
|| (op.isNamespace(StandardNamespace.PROPERTY)
&& op.isOperation(StandardOperation.GET, RhinoOperation.GETNOWARN))) {
Object constValue = getConstValue(target, op.getName());
if (constValue != null) {
MethodType mType = req.getCallSiteDescriptor().getMethodType();
// The guard returns boolean and compares the first argument to the
// target here. This works because the target is always our first argument.
MethodHandle guard = Guards.asType(Guards.getIdentityGuard(target), mType);
// Replace the actual method invocation with one that just returns a constant.
// Works because we can drop all arguments here.
MethodHandle mh =
MethodHandles.dropArguments(
MethodHandles.constant(Object.class, constValue),
0,
mType.parameterList());
if (DefaultLinker.DEBUG) {
System.out.println(op + ": constant");
}
return new GuardedInvocation(mh, guard);
}
}
return null;
}
/**
* Return the value of the specified property, but only if it's found in the root object that we
* search, and only if it's a constant. Return null otherwise, which means that we can't handle
* constants with a value of "null," which should not be a big loss.
*/
private Object getConstValue(Object t, String name) {
if (t instanceof NativeWith) {
// Support constants referenced from inside functions
return getConstValue(((NativeWith) t).getPrototype(), name);
}
assert t instanceof ScriptableObject;
try {
ScriptableObject target = (ScriptableObject) t;
// Just look in the root of the object -- don't mess around with
// nested scopes and things, to keep this simple and foolproof.
if (target.has(name, target)) {
int attributes = target.getAttributes(name);
if ((attributes & ScriptableObject.READONLY) != 0
&& (attributes & ScriptableObject.PERMANENT) != 0
&& (attributes & ScriptableObject.UNINITIALIZED_CONST) == 0) {
// If we get here then this object's value will not change for the
// lifetime of the target object.
return target.get(name, target);
}
}
} catch (RhinoException re) {
// Some implementations of ScriptableObject will fail on this operation with
// an exception, so treat that as "not found".
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy