8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt

Reviewed-by: attila, hannesw, sundar
This commit is contained in:
Marcus Lagergren 2014-09-25 15:53:47 +02:00
parent 643e8d87e6
commit da0b4cb7df
79 changed files with 2579 additions and 531 deletions

View File

@ -292,7 +292,6 @@ public class ClassGenerator {
mi.push(memInfo.getArity());
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
}
}
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {

View File

@ -28,7 +28,6 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DES
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
@ -75,10 +74,6 @@ public final class MemberInfo implements Cloneable {
* This is a specialized version of a function
*/
SPECIALIZED_FUNCTION,
/**
* This is a specialized version of a constructor
*/
SPECIALIZED_CONSTRUCTOR
}
// keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
@ -107,6 +102,12 @@ public final class MemberInfo implements Cloneable {
private Where where;
private Type linkLogicClass;
private boolean isSpecializedConstructor;
private boolean isOptimistic;
/**
* @return the kind
*/
@ -135,6 +136,57 @@ public final class MemberInfo implements Cloneable {
this.name = name;
}
/**
* Tag something as specialized constructor or not
* @param isSpecializedConstructor boolean, true if specialized constructor
*/
public void setIsSpecializedConstructor(final boolean isSpecializedConstructor) {
this.isSpecializedConstructor = isSpecializedConstructor;
}
/**
* Check if something is a specialized constructor
* @return true if specialized constructor
*/
public boolean isSpecializedConstructor() {
return isSpecializedConstructor;
}
/**
* Check if this is an optimistic builtin function
* @return true if optimistic builtin
*/
public boolean isOptimistic() {
return isOptimistic;
}
/**
* Tag something as optimitic builtin or not
* @param isOptimistic boolean, true if builtin constructor
*/
public void setIsOptimistic(final boolean isOptimistic) {
this.isOptimistic = isOptimistic;
}
/**
* Get the SpecializedFunction guard for specializations, i.e. optimistic
* builtins
* @return specialization, null if none
*/
public Type getLinkLogicClass() {
return linkLogicClass;
}
/**
* Set thre SpecializedFunction link logic class for specializations, i.e. optimistic
* builtins
* @param linkLogicClass link logic class
*/
public void setLinkLogicClass(final Type linkLogicClass) {
this.linkLogicClass = linkLogicClass;
}
/**
* @return the attributes
*/
@ -304,19 +356,6 @@ public final class MemberInfo implements Cloneable {
}
}
break;
case SPECIALIZED_CONSTRUCTOR: {
final Type returnType = Type.getReturnType(javaDesc);
if (!isJSObjectType(returnType)) {
error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType);
}
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
for (int i = 0; i < argTypes.length; i++) {
if (!isValidJSType(argTypes[i])) {
error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]);
}
}
}
break;
case FUNCTION: {
final Type returnType = Type.getReturnType(javaDesc);
if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
@ -351,7 +390,7 @@ public final class MemberInfo implements Cloneable {
break;
case SPECIALIZED_FUNCTION: {
final Type returnType = Type.getReturnType(javaDesc);
if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
if (!(isValidJSType(returnType) || (isSpecializedConstructor() && Type.VOID_TYPE == returnType))) {
error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType);
}
final Type[] argTypes = Type.getArgumentTypes(javaDesc);

View File

@ -55,6 +55,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
@ -75,13 +76,16 @@ import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT2;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT3;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_TYPE;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SPECIALIZATION;
import java.util.List;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
/**
* Base class for all method generating classes.
@ -94,6 +98,8 @@ public class MethodGenerator extends MethodVisitor {
private final Type returnType;
private final Type[] argumentTypes;
static final Type EMPTY_LINK_LOGIC_TYPE = Type.getType(LinkLogic.getEmptyLinkLogicClass());
MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
super(Main.ASM_VERSION, mv);
this.access = access;
@ -379,6 +385,11 @@ public class MethodGenerator extends MethodVisitor {
super.visitFieldInsn(GETFIELD, owner, field, desc);
}
private static boolean linkLogicIsEmpty(final Type type) {
assert EMPTY_LINK_LOGIC_TYPE != null; //type is ok for null if we are a @SpecializedFunction without any attribs
return EMPTY_LINK_LOGIC_TYPE.equals(type);
}
void memberInfoArray(final String className, final List<MemberInfo> mis) {
if (mis.isEmpty()) {
pushNull();
@ -387,12 +398,22 @@ public class MethodGenerator extends MethodVisitor {
int pos = 0;
push(mis.size());
newObjectArray(METHODHANDLE_TYPE);
newObjectArray(SPECIALIZATION_TYPE);
for (final MemberInfo mi : mis) {
dup();
push(pos++);
visitTypeInsn(NEW, SPECIALIZATION_TYPE);
dup();
visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
arrayStore(TYPE_METHODHANDLE);
final Type linkLogicClass = mi.getLinkLogicClass();
final boolean linkLogic = !linkLogicIsEmpty(linkLogicClass);
final String ctor = linkLogic ? SPECIALIZATION_INIT3 : SPECIALIZATION_INIT2;
if (linkLogic) {
visitLdcInsn(linkLogicClass);
}
visitInsn(mi.isOptimistic() ? ICONST_1 : ICONST_0);
visitMethodInsn(INVOKESPECIAL, SPECIALIZATION_TYPE, INIT, ctor, false);
arrayStore(TYPE_SPECIALIZATION);
}
}

View File

@ -37,8 +37,8 @@ import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Setter;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
@ -56,8 +56,8 @@ public final class ScriptClassInfo {
static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class);
static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class);
static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class);
static final String LINK_LOGIC_DESC = Type.getDescriptor(LinkLogic.class);
static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class);
static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
static final Map<String, Kind> annotations = new HashMap<>();
@ -69,7 +69,6 @@ public final class ScriptClassInfo {
annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR);
}
// name of the script class
@ -119,11 +118,12 @@ public final class ScriptClassInfo {
List<MemberInfo> getSpecializedConstructors() {
final List<MemberInfo> res = new LinkedList<>();
for (final MemberInfo memInfo : members) {
if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) {
if (memInfo.isSpecializedConstructor()) {
assert memInfo.getKind() == Kind.SPECIALIZED_FUNCTION;
res.add(memInfo);
}
}
return res;
return Collections.unmodifiableList(res);
}
int getPrototypeMemberCount() {
@ -175,7 +175,7 @@ public final class ScriptClassInfo {
res.add(memInfo);
}
}
return res;
return Collections.unmodifiableList(res);
}
MemberInfo findSetter(final MemberInfo getter) {

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.tools.nasgen;
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC;
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
@ -41,6 +40,7 @@ import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
@ -194,6 +194,7 @@ public class ScriptClassInfoCollector extends ClassVisitor {
final MemberInfo memInfo = new MemberInfo();
//annokind == e.g. GETTER or SPECIALIZED_FUNCTION
memInfo.setKind(annoKind);
memInfo.setJavaName(methodName);
memInfo.setJavaDesc(methodDesc);
@ -208,12 +209,18 @@ public class ScriptClassInfoCollector extends ClassVisitor {
private Integer attributes;
private Integer arity;
private Where where;
private boolean isSpecializedConstructor;
private boolean isOptimistic;
private Type linkLogicClass = MethodGenerator.EMPTY_LINK_LOGIC_TYPE;
@Override
public void visit(final String annotationName, final Object annotationValue) {
switch (annotationName) {
case "name":
this.name = (String)annotationValue;
if (name.isEmpty()) {
name = null;
}
break;
case "attributes":
this.attributes = (Integer)annotationValue;
@ -221,6 +228,17 @@ public class ScriptClassInfoCollector extends ClassVisitor {
case "arity":
this.arity = (Integer)annotationValue;
break;
case "isConstructor":
assert annoKind == Kind.SPECIALIZED_FUNCTION;
this.isSpecializedConstructor = (Boolean)annotationValue;
break;
case "isOptimistic":
assert annoKind == Kind.SPECIALIZED_FUNCTION;
this.isOptimistic = (Boolean)annotationValue;
break;
case "linkLogic":
this.linkLogicClass = (Type)annotationValue;
break;
default:
break;
}
@ -230,12 +248,19 @@ public class ScriptClassInfoCollector extends ClassVisitor {
@Override
public void visitEnum(final String enumName, final String desc, final String enumValue) {
if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
this.where = Where.valueOf(enumValue);
switch (enumName) {
case "where":
if (WHERE_ENUM_DESC.equals(desc)) {
this.where = Where.valueOf(enumValue);
}
break;
default:
break;
}
super.visitEnum(enumName, desc, enumValue);
}
@SuppressWarnings("fallthrough")
@Override
public void visitEnd() {
super.visitEnd();
@ -256,7 +281,6 @@ public class ScriptClassInfoCollector extends ClassVisitor {
case SETTER:
where = Where.INSTANCE;
break;
case SPECIALIZED_CONSTRUCTOR:
case CONSTRUCTOR:
where = Where.CONSTRUCTOR;
break;
@ -264,12 +288,18 @@ public class ScriptClassInfoCollector extends ClassVisitor {
where = Where.PROTOTYPE;
break;
case SPECIALIZED_FUNCTION:
//TODO is this correct
if (isSpecializedConstructor) {
where = Where.CONSTRUCTOR;
}
//fallthru
default:
break;
}
}
memInfo.setWhere(where);
memInfo.setLinkLogicClass(linkLogicClass);
memInfo.setIsSpecializedConstructor(isSpecializedConstructor);
memInfo.setIsOptimistic(isOptimistic);
}
};
}

View File

@ -38,7 +38,6 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DES
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -50,7 +49,6 @@ import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;

View File

@ -37,6 +37,7 @@ import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Specialization;
/**
* String constants used for code generation/instrumentation.
@ -44,20 +45,26 @@ import jdk.nashorn.internal.runtime.ScriptObject;
@SuppressWarnings("javadoc")
public interface StringConstants {
// standard jdk types, methods
static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
static final Type TYPE_OBJECT = Type.getType(Object.class);
static final Type TYPE_STRING = Type.getType(String.class);
static final Type TYPE_COLLECTION = Type.getType(Collection.class);
static final Type TYPE_COLLECTIONS = Type.getType(Collections.class);
static final Type TYPE_ARRAYLIST = Type.getType(ArrayList.class);
static final Type TYPE_LIST = Type.getType(List.class);
static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
static final Type TYPE_SPECIALIZATION = Type.getType(Specialization.class);
static final Type TYPE_SPECIALIZATION_ARRAY = Type.getType(Specialization[].class);
static final Type TYPE_OBJECT = Type.getType(Object.class);
static final Type TYPE_STRING = Type.getType(String.class);
static final Type TYPE_CLASS = Type.getType(Class.class);
static final Type TYPE_COLLECTION = Type.getType(Collection.class);
static final Type TYPE_COLLECTIONS = Type.getType(Collections.class);
static final Type TYPE_ARRAYLIST = Type.getType(ArrayList.class);
static final Type TYPE_LIST = Type.getType(List.class);
static final String CLINIT = "<clinit>";
static final String INIT = "<init>";
static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
static final String SPECIALIZATION_TYPE = TYPE_SPECIALIZATION.getInternalName();
static final String SPECIALIZATION_INIT2 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, Type.getType(boolean.class));
static final String SPECIALIZATION_INIT3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, TYPE_CLASS, Type.getType(boolean.class));
static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
static final String STRING_TYPE = TYPE_STRING.getInternalName();
@ -122,11 +129,11 @@ public interface StringConstants {
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_SPECIALIZATION_ARRAY);
// ScriptObject
static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName();

View File

@ -52,41 +52,49 @@ public class BufferArray extends AbstractJSObject {
// underlying nio buffer
private final DoubleBuffer buf;
public BufferArray(int size) {
/**
* Constructor
* @param size initial size
*/
public BufferArray(final int size) {
buf = DoubleBuffer.allocate(size);
}
public BufferArray(DoubleBuffer buf) {
/**
* Constructur
* @param buf {@link DoubleBuffer} to link to
*/
public BufferArray(final DoubleBuffer buf) {
this.buf = buf;
}
// called to check if indexed property exists
@Override
public boolean hasSlot(int index) {
public boolean hasSlot(final int index) {
return index > 0 && index < buf.capacity();
}
// get the value from that index
@Override
public Object getSlot(int index) {
public Object getSlot(final int index) {
return buf.get(index);
}
// set the value at that index
@Override
public void setSlot(int index, Object value) {
public void setSlot(final int index, final Object value) {
buf.put(index, ((Number)value).doubleValue());
}
// do you have a property of that given name?
@Override
public boolean hasMember(String name) {
public boolean hasMember(final String name) {
return "length".equals(name) || "buf".equals(name);
}
// get the value of that named property
@Override
public Object getMember(String name) {
public Object getMember(final String name) {
switch (name) {
case "length":
return buf.capacity();
@ -94,7 +102,7 @@ public class BufferArray extends AbstractJSObject {
// return a 'function' value for this property
return new AbstractJSObject() {
@Override
public Object call(Object thiz, Object... args) {
public Object call(final Object thiz, final Object... args) {
return BufferArray.this.buf;
}

View File

@ -136,6 +136,7 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
}
};
final Set<Expression> argumentsFound = new HashSet<>();
final Deque<Set<Expression>> stack = new ArrayDeque<>();
//ensure that arguments is only passed as arg to apply
try {
@ -145,7 +146,11 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
}
private boolean isArguments(final Expression expr) {
return expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName());
if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) {
argumentsFound.add(expr);
return true;
}
return false;
}
private boolean isParam(final String name) {
@ -159,7 +164,7 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
@Override
public Node leaveIdentNode(final IdentNode identNode) {
if (isParam(identNode.getName()) || ARGUMENTS.equals(identNode.getName()) && !isCurrentArg(identNode)) {
if (isParam(identNode.getName()) || isArguments(identNode) && !isCurrentArg(identNode)) {
throw uoe; //avoid filling in stack trace
}
return identNode;
@ -186,7 +191,9 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
}
});
} catch (final UnsupportedOperationException e) {
log.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
if (!argumentsFound.isEmpty()) {
log.fine("'arguments' is used but escapes, or is reassigned in '" + functionNode.getName() + "'. Aborting");
}
return true; //bad
}
@ -267,9 +274,9 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
return false;
}
if (!Global.instance().isSpecialNameValid("apply")) {
if (!Global.isBuiltinFunctionPrototypeApply()) {
log.fine("Apply transform disabled: apply/call overridden");
assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
assert !Global.isBuiltinFunctionPrototypeCall() : "call and apply should have the same SwitchPoint";
return false;
}

View File

@ -51,15 +51,14 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.className;
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
@ -160,8 +159,12 @@ public class ClassEmitter implements Emitter {
this.methodNames = new HashSet<>();
}
/**
* Return the method names encountered
* @return method names
*/
public Set<String> getMethodNames() {
return methodNames;
return Collections.unmodifiableSet(methodNames);
}
/**

View File

@ -60,6 +60,10 @@ public final class CompileUnit implements Comparable<CompileUnit> {
emittedUnitCount++;
}
/**
* Get the amount of emitted compile units so far in the system
* @return emitted compile unit count
*/
public static int getEmittedUnitCount() {
return emittedUnitCount;
}
@ -72,6 +76,10 @@ public final class CompileUnit implements Comparable<CompileUnit> {
return isUsed;
}
/**
* Check if a compile unit has code, not counting inits and clinits
* @return true of if there is "real code" in the compile unit
*/
public boolean hasCode() {
return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
}

View File

@ -71,7 +71,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Collection;
@ -99,13 +98,13 @@ import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.ArgumentSetter;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.RewriteException;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@ -180,9 +179,6 @@ public class MethodEmitter implements Emitter {
/** Bootstrap for array populators */
private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor());
/** Bootstrap for global name invalidation */
private static final Handle INVALIDATE_NAME_BOOTSTRAP = new Handle(H_INVOKESTATIC, Global.BOOTSTRAP.className(), Global.BOOTSTRAP.name(), Global.BOOTSTRAP.descriptor());
/**
* Constructor - internal use from ClassEmitter only
* @see ClassEmitter#method
@ -2131,10 +2127,13 @@ public class MethodEmitter implements Emitter {
}
MethodEmitter invalidateSpecialName(final String name) {
//this is a nop if the global hasn't registered this as a special name - we can just ignore it
if (Global.instance().isSpecialName(name)) {
debug("dynamic_invalidate_name", "name=", name);
method.visitInvokeDynamicInsn(name, "()V", INVALIDATE_NAME_BOOTSTRAP);
switch (name) {
case "apply":
case "call":
debug("invalidate_name", "name=", name);
load("Function");
invoke(ScriptRuntime.INVALIDATE_RESERVED_BUILTIN_NAME);
break;
}
return this;
}

View File

@ -429,7 +429,6 @@ public final class OptimisticTypesPersistence {
}
private static void doCleanup() throws IOException {
final long start = System.nanoTime();
final Path[] files = getAllRegularFilesInLastModifiedOrder();
final int nFiles = files.length;
final int filesToDelete = Math.max(0, nFiles - MAX_FILES);
@ -445,7 +444,6 @@ public final class OptimisticTypesPersistence {
}
files[i] = null; // gc eligible
};
final long duration = System.nanoTime() - start;
}
private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
@ -497,7 +495,7 @@ public final class OptimisticTypesPersistence {
private static long getTime(final Path path) {
try {
return Files.getLastModifiedTime(path).toMillis();
} catch (IOException e) {
} catch (final IOException e) {
// All files for which we can't retrieve the last modified date will be considered oldest.
return -1L;
}

View File

@ -238,17 +238,21 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* Note that even IS_STRICT is one such flag but that requires special handling.
*/
// parser, lower debugging this function
/** parser, print parse tree */
public static final int IS_PRINT_PARSE = 1 << 18;
/** parser, print lower parse tree */
public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
/** parser, print AST */
public static final int IS_PRINT_AST = 1 << 20;
/** parser, print lower AST */
public static final int IS_PRINT_LOWER_AST = 1 << 21;
/** parser, print symbols */
public static final int IS_PRINT_SYMBOLS = 1 << 22;
// callsite tracing, profiling within this function
/** profile callsites in this function? */
public static final int IS_PROFILE = 1 << 23;
// callsite tracing, profiling within this function
/** trace callsite enterexit in this function? */
public static final int IS_TRACE_ENTEREXIT = 1 << 24;
@ -337,7 +341,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
private FunctionNode(
final FunctionNode functionNode,
final long lastToken,
Object endParserState,
final Object endParserState,
final int flags,
final String name,
final Type returnType,

View File

@ -237,6 +237,10 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
return value;
}
private static Expression[] valueToArray(final List<Expression> value) {
return value.toArray(new Expression[value.size()]);
}
/**
* Create a new null literal
*
@ -981,10 +985,9 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final List<Expression> value) {
return new ArrayLiteralNode(token, finish, value.toArray(new Expression[value.size()]));
return new ArrayLiteralNode(token, finish, valueToArray(value));
}
/**
* Create a new array literal based on a parent node (source, token, finish)
*
@ -994,7 +997,7 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final List<Expression> value) {
return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Expression[value.size()]));
return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), valueToArray(value));
}
/**

View File

@ -448,14 +448,25 @@ public final class Symbol implements Comparable<Symbol> {
return (flags & IS_FUNCTION_SELF) != 0;
}
/**
* Is this a block scoped symbol
* @return true if block scoped
*/
public boolean isBlockScoped() {
return isLet() || isConst();
}
/**
* Has this symbol been declared
* @return true if declared
*/
public boolean hasBeenDeclared() {
return (flags & HAS_BEEN_DECLARED) != 0;
}
/**
* Mark this symbol as declared
*/
public void setHasBeenDeclared() {
if (!hasBeenDeclared()) {
flags |= HAS_BEEN_DECLARED;

View File

@ -116,6 +116,10 @@ public final class MethodHandleFactory {
private static final String VOID_TAG = "[VOID]";
private static void err(final String str) {
Context.getContext().getErr().println(str);
}
/**
* Tracer that is applied before a value is returned from the traced function. It will output the return
* value and its class
@ -124,13 +128,16 @@ public final class MethodHandleFactory {
* @return return value unmodified
*/
static Object traceReturn(final DebugLogger logger, final Object value) {
if (logger.isEnabled()) {
final String str = " return" +
(VOID_TAG.equals(value) ?
";" :
" " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
final String str = " return" +
(VOID_TAG.equals(value) ?
";" :
" " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
if (logger == null) {
err(str);
} else if (logger.isEnabled()) {
logger.log(TRACE_LEVEL, str);
}
return value;
}
@ -169,8 +176,11 @@ public final class MethodHandleFactory {
}
}
assert logger != null;
logger.log(TRACE_LEVEL, sb);
if (logger == null) {
err(sb.toString());
} else {
logger.log(TRACE_LEVEL, sb);
}
stacktrace(logger);
}
@ -181,7 +191,12 @@ public final class MethodHandleFactory {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(baos);
new Throwable().printStackTrace(ps);
logger.log(TRACE_LEVEL, baos.toString());
final String st = baos.toString();
if (logger == null) {
err(st);
} else {
logger.log(TRACE_LEVEL, st);
}
}
private static String argString(final Object arg) {
@ -201,12 +216,24 @@ public final class MethodHandleFactory {
if (arg instanceof ScriptObject) {
return arg.toString() +
" (map=" + Debug.id(((ScriptObject)arg).getMap()) +
")";
')';
}
return arg.toString();
}
/**
* Add a debug printout to a method handle, tracing parameters and return values
* Output will be unconditional to stderr
*
* @param mh method handle to trace
* @param tag start of trace message
* @return traced method handle
*/
public static MethodHandle addDebugPrintout(final MethodHandle mh, final Object tag) {
return addDebugPrintout(null, Level.OFF, mh, 0, true, tag);
}
/**
* Add a debug printout to a method handle, tracing parameters and return values
*
@ -221,6 +248,20 @@ public final class MethodHandleFactory {
}
/**
* Add a debug printout to a method handle, tracing parameters and return values
* Output will be unconditional to stderr
*
* @param mh method handle to trace
* @param paramStart first param to print/trace
* @param printReturnValue should we print/trace return value if available?
* @param tag start of trace message
* @return traced method handle
*/
public static MethodHandle addDebugPrintout(final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
return addDebugPrintout(null, Level.OFF, mh, paramStart, printReturnValue, tag);
}
/**
* Add a debug printout to a method handle, tracing parameters and return values
*
* @param logger a specific logger to which to write the output
@ -240,7 +281,6 @@ public final class MethodHandleFactory {
return mh;
}
assert logger != null;
assert TRACE != null;
MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart);
@ -427,6 +467,12 @@ public final class MethodHandleFactory {
return debug(mh, "constant", type, value);
}
@Override
public MethodHandle identity(final Class<?> type) {
final MethodHandle mh = MethodHandles.identity(type);
return debug(mh, "identity", type);
}
@Override
public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
final MethodHandle mh = handle.asCollector(arrayType, arrayLength);

View File

@ -172,6 +172,15 @@ public interface MethodHandleFunctionality {
*/
public MethodHandle constant(Class<?> type, Object value);
/**
* Wrapper for {@link java.lang.invoke.MethodHandles#identity(Class)}
*
* @param type type of value
*
* @return method handle that returns identity argument
*/
public MethodHandle identity(Class<?> type);
/**
* Wrapper for {@link java.lang.invoke.MethodHandle#asType(MethodType)}
*

View File

@ -31,6 +31,7 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;

View File

@ -25,23 +25,19 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
@ -52,8 +48,6 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Property;
@ -72,6 +66,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.ScriptingFunctions;
import jdk.nashorn.internal.runtime.Specialization;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@ -107,10 +102,6 @@ public final class Global extends ScriptObject implements Scope {
* it's when you start adding property checks for said builtins you have
* problems with guard speed.
*/
public final Map<String, SwitchPoint> optimisticFunctionMap;
/** Name invalidator for things like call/apply */
public static final Call BOOTSTRAP = staticCall(MethodHandles.lookup(), Global.class, "invalidateNameBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
/** Nashorn extension: arguments array */
@Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
@ -428,9 +419,6 @@ public final class Global extends ScriptObject implements Scope {
private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class);
/** Invalidate a reserved name, such as "apply" or "call" if assigned */
public MethodHandle INVALIDATE_RESERVED_NAME = MH.bindTo(findOwnMH_V("invalidateReservedName", void.class, String.class), this);
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@ -482,7 +470,6 @@ public final class Global extends ScriptObject implements Scope {
super(checkAndGetMap(context));
this.context = context;
this.setIsScope();
this.optimisticFunctionMap = new HashMap<>();
//we can only share one instance of Global constants between globals, or we consume way too much
//memory - this is good enough for most programs
while (gcsInstance.get() == null) {
@ -1244,6 +1231,40 @@ public final class Global extends ScriptObject implements Scope {
return instance.function == instance.getBuiltinFunction();
}
/**
* Get the switchpoint used to check property changes for Function.prototype.apply
* @return the switchpoint guarding apply (same as guarding call, and everything else in function)
*/
public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
}
private static boolean isBuiltinFunctionProperty(final String name) {
final Global instance = Global.instance();
final ScriptFunction builtinFunction = instance.getBuiltinFunction();
if (builtinFunction == null) {
return false; //conservative for compile-only mode
}
final boolean isBuiltinFunction = instance.function == builtinFunction;
return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
}
/**
* Check if the Function.prototype.apply has not been replaced
* @return true if Function.prototype.apply has been replaced
*/
public static boolean isBuiltinFunctionPrototypeApply() {
return isBuiltinFunctionProperty("apply");
}
/**
* Check if the Function.prototype.apply has not been replaced
* @return true if Function.prototype.call has been replaced
*/
public static boolean isBuiltinFunctionPrototypeCall() {
return isBuiltinFunctionProperty("call");
}
private ScriptFunction getBuiltinJSAdapter() {
return builtinJSAdapter;
}
@ -1688,6 +1709,12 @@ public final class Global extends ScriptObject implements Scope {
splitState = state;
}
private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
final T func = initConstructor(name, clazz);
tagBuiltinProperties(name, func);
return func;
}
private void init(final ScriptEngine engine) {
assert Context.getGlobal() == this : "this global is not set as current";
@ -1702,8 +1729,19 @@ public final class Global extends ScriptObject implements Scope {
// initialize global function properties
this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
new MethodHandle[] { GlobalFunctions.PARSEINT_OI, GlobalFunctions.PARSEINT_O });
this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
new Specialization[] {
new Specialization(GlobalFunctions.PARSEINT_Z),
new Specialization(GlobalFunctions.PARSEINT_I),
new Specialization(GlobalFunctions.PARSEINT_J),
new Specialization(GlobalFunctions.PARSEINT_OI),
new Specialization(GlobalFunctions.PARSEINT_O) });
this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN,
new Specialization[] {
new Specialization(GlobalFunctions.IS_NAN_I),
new Specialization(GlobalFunctions.IS_NAN_J),
new Specialization(GlobalFunctions.IS_NAN_D) });
this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN);
this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE);
@ -1720,15 +1758,15 @@ public final class Global extends ScriptObject implements Scope {
this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT);
// built-in constructors
this.builtinArray = initConstructor("Array", ScriptFunction.class);
this.builtinBoolean = initConstructor("Boolean", ScriptFunction.class);
this.builtinDate = initConstructor("Date", ScriptFunction.class);
this.builtinJSON = initConstructor("JSON", ScriptObject.class);
this.builtinJSAdapter = initConstructor("JSAdapter", ScriptFunction.class);
this.builtinMath = initConstructor("Math", ScriptObject.class);
this.builtinNumber = initConstructor("Number", ScriptFunction.class);
this.builtinRegExp = initConstructor("RegExp", ScriptFunction.class);
this.builtinString = initConstructor("String", ScriptFunction.class);
this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class);
this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class);
// initialize String.prototype.length to 0
// add String.prototype.length
@ -1830,6 +1868,8 @@ public final class Global extends ScriptObject implements Scope {
// Error.prototype.message = "";
errorProto.set(NativeError.MESSAGE, "", 0);
tagBuiltinProperties("Error", builtinError);
this.builtinEvalError = initErrorSubtype("EvalError", errorProto);
this.builtinRangeError = initErrorSubtype("RangeError", errorProto);
this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
@ -1844,6 +1884,7 @@ public final class Global extends ScriptObject implements Scope {
prototype.set(NativeError.NAME, name, 0);
prototype.set(NativeError.MESSAGE, "", 0);
prototype.setInitialProto(errorProto);
tagBuiltinProperties(name, cons);
return cons;
}
@ -1910,17 +1951,18 @@ public final class Global extends ScriptObject implements Scope {
}
private void initTypedArray() {
this.builtinArrayBuffer = initConstructor("ArrayBuffer", ScriptFunction.class);
this.builtinDataView = initConstructor("DataView", ScriptFunction.class);
this.builtinInt8Array = initConstructor("Int8Array", ScriptFunction.class);
this.builtinUint8Array = initConstructor("Uint8Array", ScriptFunction.class);
this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray", ScriptFunction.class);
this.builtinInt16Array = initConstructor("Int16Array", ScriptFunction.class);
this.builtinUint16Array = initConstructor("Uint16Array", ScriptFunction.class);
this.builtinInt32Array = initConstructor("Int32Array", ScriptFunction.class);
this.builtinUint32Array = initConstructor("Uint32Array", ScriptFunction.class);
this.builtinFloat32Array = initConstructor("Float32Array", ScriptFunction.class);
this.builtinFloat64Array = initConstructor("Float64Array", ScriptFunction.class);
this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
}
private void copyBuiltins() {
@ -1993,10 +2035,6 @@ public final class Global extends ScriptObject implements Scope {
return UNDEFINED;
}
/**
* These classes are generated by nasgen tool and so we have to use
* reflection to load and create new instance of these classes.
*/
private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
try {
// Assuming class name pattern for built-in JS constructors.
@ -2021,12 +2059,52 @@ public final class Global extends ScriptObject implements Scope {
}
res.setIsBuiltin();
return res;
} catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
list.addAll(Arrays.asList(func.getMap().getProperties()));
if (func instanceof ScriptFunction) {
final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
if (proto != null) {
list.addAll(Arrays.asList(proto.getMap().getProperties()));
}
}
final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
if (prop != null) {
list.add(prop);
}
return list;
}
/**
* Given a builtin object, traverse its properties recursively and associate them with a name that
* will be a key to their invalidation switchpoint.
* @param name name for key
* @param func builtin script object
*/
private void tagBuiltinProperties(final String name, final ScriptObject func) {
SwitchPoint sp = context.getBuiltinSwitchPoint(name);
if (sp == null) {
sp = context.newBuiltinSwitchPoint(name);
}
//get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
//one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
prop.setBuiltinSwitchPoint(sp);
}
}
// Function and Object constructors are inter-dependent. Also,
// Function.prototype
// functions are not properly initialized. We fix the references here.
@ -2035,7 +2113,8 @@ public final class Global extends ScriptObject implements Scope {
// to play with object references carefully!!
private void initFunctionAndObject() {
// First-n-foremost is Function
this.builtinFunction = initConstructor("Function", ScriptFunction.class);
this.builtinFunction = initConstructor("Function", ScriptFunction.class);
// create global anonymous function
final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
@ -2101,13 +2180,6 @@ public final class Global extends ScriptObject implements Scope {
}
}
//make sure apply and call have the same invalidation switchpoint
final SwitchPoint sp = new SwitchPoint();
optimisticFunctionMap.put("apply", sp);
optimisticFunctionMap.put("call", sp);
getFunctionPrototype().getProperty("apply").setChangeCallback(sp);
getFunctionPrototype().getProperty("call").setChangeCallback(sp);
properties = getObjectPrototype().getMap().getProperties();
for (final jdk.nashorn.internal.runtime.Property property : properties) {
@ -2125,10 +2197,10 @@ public final class Global extends ScriptObject implements Scope {
}
}
}
}
private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findVirtual(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
tagBuiltinProperties("Object", builtinObject);
tagBuiltinProperties("Function", builtinFunction);
tagBuiltinProperties("Function", anon);
}
private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
@ -2147,62 +2219,4 @@ public final class Global extends ScriptObject implements Scope {
protected boolean isGlobal() {
return true;
}
/**
* Check if there is a switchpoint for a reserved name. If there
* is, it must be invalidated upon properties with this name
* @param name property name
* @return switchpoint for invalidating this property, or null if not registered
*/
public SwitchPoint getChangeCallback(final String name) {
return optimisticFunctionMap.get(name);
}
/**
* Is this a special name, that might be subject to invalidation
* on write, such as "apply" or "call"
* @param name name to check
* @return true if special name
*/
public boolean isSpecialName(final String name) {
return getChangeCallback(name) != null;
}
/**
* Check if a reserved property name is invalidated
* @param name property name
* @return true if someone has written to it since Global was instantiated
*/
public boolean isSpecialNameValid(final String name) {
final SwitchPoint sp = getChangeCallback(name);
return sp != null && !sp.hasBeenInvalidated();
}
/**
* Tag a reserved name as invalidated - used when someone writes
* to a property with this name - overly conservative, but link time
* is too late to apply e.g. apply-&gt;call specialization
* @param name property name
*/
public void invalidateReservedName(final String name) {
final SwitchPoint sp = getChangeCallback(name);
if (sp != null) {
getContext().getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
}
}
/**
* Bootstrapper for invalidating a builtin name
* @param lookup lookup
* @param name name to invalidate
* @param type methodhandle type
* @return callsite for invalidator
*/
public static CallSite invalidateNameBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type) {
final MethodHandle target = MH.insertArguments(Global.instance().INVALIDATE_RESERVED_NAME, 0, name);
return new ConstantCallSite(target);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2014, 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
@ -33,8 +33,8 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -52,12 +52,13 @@ import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Setter;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.OptimisticBuiltins;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
@ -67,17 +68,20 @@ import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.arrays.ContinuousArrayData;
import jdk.nashorn.internal.runtime.arrays.IntElements;
import jdk.nashorn.internal.runtime.arrays.IntOrLongElements;
import jdk.nashorn.internal.runtime.arrays.IteratorAction;
import jdk.nashorn.internal.runtime.arrays.NumericElements;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Runtime representation of a JavaScript array. NativeArray only holds numeric
* keyed values. All other values are stored in spill.
*/
@ScriptClass("Array")
public final class NativeArray extends ScriptObject {
public final class NativeArray extends ScriptObject implements OptimisticBuiltins {
private static final Object JOIN = new Object();
private static final Object EVERY_CALLBACK_INVOKER = new Object();
private static final Object SOME_CALLBACK_INVOKER = new Object();
@ -88,6 +92,16 @@ public final class NativeArray extends ScriptObject {
private static final Object CALL_CMP = new Object();
private static final Object TO_LOCALE_STRING = new Object();
private SwitchPoint lengthMadeNotWritableSwitchPoint;
private PushLinkLogic pushLinkLogic;
private PopLinkLogic popLinkLogic;
/**
* Index for the modification SwitchPoint that triggers when length
* becomes not writable
*/
private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0;
/*
* Constructors.
*/
@ -420,6 +434,28 @@ public final class NativeArray extends ScriptObject {
return getArray().asObjectArray();
}
@Override
public void setIsLengthNotWritable() {
super.setIsLengthNotWritable();
/*
* Switchpoints are created lazily. If we link any push or pop site,
* we need to create the "length made not writable" switchpoint, if it
* doesn't exist.
*
* If the switchpoint already exists, we will find it here, and invalidate
* it, invalidating all previous callsites that use it.
*
* If the switchpoint doesn't exist, no push/pop has been linked so far,
* because that would create it too. We invalidate it immediately and the
* check link logic for all future callsites will fail immediately at link
* time
*/
if (lengthMadeNotWritableSwitchPoint == null) {
lengthMadeNotWritableSwitchPoint = new SwitchPoint();
}
SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint });
}
/**
* ECMA 15.4.3.2 Array.isArray ( arg )
*
@ -638,7 +674,7 @@ public final class NativeArray extends ScriptObject {
* @param self self reference
* @return the new NativeArray
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self) {
return new NativeArray(0);
}
@ -653,7 +689,7 @@ public final class NativeArray extends ScriptObject {
* @param element first element
* @return the new NativeArray
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object construct(final boolean newObj, final Object self, final boolean element) {
return new NativeArray(new Object[] { element });
}
@ -668,7 +704,7 @@ public final class NativeArray extends ScriptObject {
* @param length array length
* @return the new NativeArray
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final int length) {
if (length >= 0) {
return new NativeArray(length);
@ -687,7 +723,7 @@ public final class NativeArray extends ScriptObject {
* @param length array length
* @return the new NativeArray
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final long length) {
if (length >= 0L && length <= JSType.MAX_UINT) {
return new NativeArray(length);
@ -706,7 +742,7 @@ public final class NativeArray extends ScriptObject {
* @param length array length
* @return the new NativeArray
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final double length) {
final long uint32length = JSType.toUint32(length);
@ -721,7 +757,7 @@ public final class NativeArray extends ScriptObject {
* ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
*
* @param self self reference
* @param args arguments to concat
* @param args arguments
* @return resulting NativeArray
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
@ -792,6 +828,68 @@ public final class NativeArray extends ScriptObject {
return sb.toString();
}
/**
* Specialization of pop for ContinuousArrayData
* The link guard checks that the array is continuous AND not empty.
* The runtime guard checks that the guard is continuous (CCE otherwise)
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @return element popped
* @throws ClassCastException if array is empty, facilitating Undefined return value
*/
@SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
public static int popInt(final Object self) {
//must be non empty IntArrayData
return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt();
}
/**
* Specialization of pop for ContinuousArrayData
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @return element popped
* @throws ClassCastException if array is empty, facilitating Undefined return value
*/
@SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
public static long popLong(final Object self) {
//must be non empty Int or LongArrayData
return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong();
}
/**
* Specialization of pop for ContinuousArrayData
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @return element popped
* @throws ClassCastException if array is empty, facilitating Undefined return value
*/
@SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
public static double popDouble(final Object self) {
//must be non empty int long or double array data
return getContinuousNonEmptyArrayDataCCE(self, NumericElements.class).fastPopDouble();
}
/**
* Specialization of pop for ContinuousArrayData
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @return element popped
* @throws ClassCastException if array is empty, facilitating Undefined return value
*/
@SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
public static Object popObject(final Object self) {
//can be any data, because the numeric ones will throw cce and force relink
return getContinuousArrayDataCCE(self, null).fastPopObject();
}
/**
* ECMA 15.4.4.6 Array.prototype.pop ()
*
@ -826,6 +924,62 @@ public final class NativeArray extends ScriptObject {
}
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @param arg a primitive to push
* @return array length after push
*/
@SpecializedFunction(linkLogic=PushLinkLogic.class)
public static long push(final Object self, final int arg) {
return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg);
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @param arg a primitive to push
* @return array length after push
*/
@SpecializedFunction(linkLogic=PushLinkLogic.class)
public static long push(final Object self, final long arg) {
return getContinuousArrayDataCCE(self, Long.class).fastPush(arg);
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @param arg a primitive to push
* @return array length after push
*/
@SpecializedFunction(linkLogic=PushLinkLogic.class)
public static long push(final Object self, final double arg) {
return getContinuousArrayDataCCE(self, Double.class).fastPush(arg);
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
* Primitive specialization, {@link LinkLogic}
*
* @param self self reference
* @param arg a primitive to push
* @return array length after push
*/
@SpecializedFunction(name="push", linkLogic=PushLinkLogic.class)
public static long pushObject(final Object self, final Object arg) {
return getContinuousArrayDataCCE(self, Object.class).fastPush(arg);
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
@ -856,61 +1010,6 @@ public final class NativeArray extends ScriptObject {
}
}
/**
* ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single int argument
*
* @param self self reference
* @param arg argument to push
* @return array after pushes
*/
/* @SpecializedFunction
public static long push(final Object self, final int arg) {
try {
final ScriptObject sobj = (ScriptObject)self;
final ArrayData arrayData = sobj.getArray();
final long length = arrayData.length();
if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
return length + 1;
}
long len = JSType.toUint32(sobj.getLength());
sobj.set(len++, arg, true);
sobj.set("length", len, true);
return len;
} catch (final ClassCastException | NullPointerException e) {
throw typeError("not.an.object", ScriptRuntime.safeToString(self));
}
}
*/
/**
* ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single number argument
*
* @param self self reference
* @param arg argument to push
* @return array after pushes
*/
/* @SpecializedFunction
public static long push(final Object self, final double arg) {
try {
final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray();
final long length = arrayData.length();
if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
return length + 1;
}
long len = JSType.toUint32(sobj.getLength());
sobj.set(len++, arg, true);
sobj.set("length", len, true);
return len;
} catch (final ClassCastException | NullPointerException e) {
throw typeError("not.an.object", ScriptRuntime.safeToString(self));
}
}
*/
/**
* ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument
*
@ -925,7 +1024,7 @@ public final class NativeArray extends ScriptObject {
final ArrayData arrayData = sobj.getArray();
final long length = arrayData.length();
if (bulkable(sobj) && length < JSType.MAX_UINT) {
sobj.setArray(arrayData.push(true, arg)); //ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
sobj.setArray(arrayData.push(true, arg));
return length + 1;
}
@ -1584,6 +1683,192 @@ public final class NativeArray extends ScriptObject {
@Override
public String toString() {
return "NativeArray@" + Debug.id(this) + '@' + getArray().getClass().getSimpleName();
return "NativeArray@" + Debug.id(this) + " [" + getArray().getClass().getSimpleName() + ']';
}
@Override
public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
if (clazz == PushLinkLogic.class) {
return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
} else if (clazz == PopLinkLogic.class) {
return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
}
return null;
}
@Override
public boolean hasPerInstanceAssumptions() {
return true; //length switchpoint
}
/**
* This is an abstract super class that contains common functionality for all
* specialized optimistic builtins in NativeArray. For example, it handles the
* modification switchpoint which is touched when length is written.
*/
private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic {
private final NativeArray array;
protected ArrayLinkLogic(final NativeArray array) {
this.array = array;
}
private SwitchPoint getSwitchPoint() {
return array.lengthMadeNotWritableSwitchPoint;
}
private SwitchPoint newSwitchPoint() {
assert array.lengthMadeNotWritableSwitchPoint == null;
final SwitchPoint sp = new SwitchPoint();
array.lengthMadeNotWritableSwitchPoint = sp;
return sp;
}
protected static ContinuousArrayData getContinuousArrayData(final Object self) {
try {
//cast to NativeArray, to avoid cases like x = {0:0, 1:1}, x.length = 2, where we can't use the array push/pop
return (ContinuousArrayData)((NativeArray)self).getArray();
} catch (final Exception e) {
return null;
}
}
/**
* Push and pop callsites can throw ClassCastException as a mechanism to have them
* relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
* for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
*/
@Override
public Class<? extends Throwable> getRelinkException() {
return ClassCastException.class;
}
@Override
public boolean hasModificationSwitchPoints() {
return getSwitchPoint() != null;
}
@Override
public boolean hasModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
return hasModificationSwitchPoints();
}
@Override
public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
SwitchPoint sp = getSwitchPoint();
if (sp == null) {
sp = newSwitchPoint();
}
return sp;
}
@Override
public SwitchPoint[] getOrCreateModificationSwitchPoints() {
return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) };
}
@Override
public void invalidateModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
invalidateModificationSwitchPoints();
}
@Override
public void invalidateModificationSwitchPoints() {
final SwitchPoint sp = getSwitchPoint();
assert sp != null : "trying to invalidate non-existant modified SwitchPoint";
if (!sp.hasBeenInvalidated()) {
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
}
}
@Override
public boolean hasInvalidatedModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
return hasInvalidatedModificationSwitchPoints();
}
@Override
public boolean hasInvalidatedModificationSwitchPoints() {
final SwitchPoint sp = getSwitchPoint();
return sp != null && !sp.hasBeenInvalidated();
}
}
/**
* This is linker logic for optimistic pushes
*/
private static final class PushLinkLogic extends ArrayLinkLogic {
private PushLinkLogic(final NativeArray array) {
super(array);
}
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
return getContinuousArrayData(self) != null;
}
}
/**
* This is linker logic for optimistic pops
*/
private static final class PopLinkLogic extends ArrayLinkLogic {
private PopLinkLogic(final NativeArray array) {
super(array);
}
/**
* We need to check if we are dealing with a continuous non empty array data here,
* as pop with a primitive return value returns undefined for arrays with length 0
*/
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
final ContinuousArrayData data = getContinuousNonEmptyArrayData(self);
if (data != null) {
final Class<?> elementType = data.getElementType();
final Class<?> returnType = desc.getMethodType().returnType();
final boolean typeFits = JSType.getAccessorTypeIndex(returnType) >= JSType.getAccessorTypeIndex(elementType);
return typeFits;
}
return false;
}
private ContinuousArrayData getContinuousNonEmptyArrayData(final Object self) {
final ContinuousArrayData data = getContinuousArrayData(self);
if (data != null) {
return data.length() == 0 ? null : data;
}
return null;
}
}
//runtime calls for push and pops. they could be used as guards, but they also perform the runtime logic,
//so rather than synthesizing them into a guard method handle that would also perform the push on the
//retrieved receiver, we use this as runtime logic
//TODO - fold these into the Link logics, but I'll do that as a later step, as I want to do a checkin
//where everything works first
private static final <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) {
try {
@SuppressWarnings("unchecked")
final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray();
if (data.length() != 0L) {
return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int
}
} catch (final NullPointerException e) {
//fallthru
}
throw new ClassCastException();
}
private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
try {
return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
} catch (final NullPointerException e) {
throw new ClassCastException();
}
}
}

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.nashorn.internal.objects.annotations.Attribute;
@ -35,7 +34,6 @@ import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
@ -156,7 +154,7 @@ public class NativeDataView extends ScriptObject {
* @param offset offset in bytes from the start of the ArrayBuffer
* @return newly constructed DataView object
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) {
if (!(arrBuf instanceof NativeArrayBuffer)) {
throw typeError("not.an.arraybuffer.in.dataview");
@ -174,7 +172,7 @@ public class NativeDataView extends ScriptObject {
* @param length is the number of bytes from the offset that this DataView will reference
* @return newly constructed DataView object
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) {
if (!(arrBuf instanceof NativeArrayBuffer)) {
throw typeError("not.an.arraybuffer.in.dataview");

View File

@ -30,7 +30,6 @@ import static java.lang.Double.isInfinite;
import static java.lang.Double.isNaN;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.Callable;
@ -38,7 +37,7 @@ import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.parser.DateParser;
import jdk.nashorn.internal.runtime.ConsString;
@ -155,7 +154,7 @@ public final class NativeDate extends ScriptObject {
* @param self self references
* @return Date representing now
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object construct(final boolean isNew, final Object self) {
final NativeDate result = new NativeDate();
return isNew ? result : toStringImpl(result, FORMAT_DATE_TIME);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -84,6 +83,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
super(((FloatBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
public Class<?> getElementType() {
return double.class;
}
@Override
protected MethodHandle getGetElem() {
return GET_ELEM;

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -94,6 +93,11 @@ public final class NativeFloat64Array extends ArrayBufferView {
return SET_ELEM;
}
@Override
public Class<?> getElementType() {
return double.class;
}
private double getElem(final int index) {
try {
return nb.get(index);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -95,6 +94,11 @@ public final class NativeInt16Array extends ArrayBufferView {
return SET_ELEM;
}
@Override
public Class<?> getElementType() {
return int.class;
}
private int getElem(final int index) {
try {
return nb.get(index);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -112,6 +111,11 @@ public final class NativeInt32Array extends ArrayBufferView {
}
}
@Override
public Class<?> getElementType() {
return int.class;
}
@Override
public int getInt(final int index) {
return getElem(index);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -93,6 +92,11 @@ public final class NativeInt8Array extends ArrayBufferView {
return SET_ELEM;
}
@Override
public Class<?> getElementType() {
return int.class;
}
private int getElem(final int index) {
try {
return nb.get(index);

View File

@ -48,7 +48,6 @@ import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.scripts.JO;

View File

@ -33,13 +33,14 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.BitVector;
import jdk.nashorn.internal.runtime.JSType;
@ -143,7 +144,7 @@ public final class NativeRegExp extends ScriptObject {
* @param self self reference
* @return new NativeRegExp
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self) {
return new NativeRegExp("", "");
}
@ -158,7 +159,7 @@ public final class NativeRegExp extends ScriptObject {
* @param pattern pattern
* @return new NativeRegExp
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) {
return newRegExp(pattern, UNDEFINED);
}
@ -174,7 +175,7 @@ public final class NativeRegExp extends ScriptObject {
* @param flags flags
* @return new NativeRegExp
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) {
return newRegExp(pattern, flags);
}

View File

@ -29,7 +29,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -49,11 +48,12 @@ import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.OptimisticBuiltins;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@ -67,7 +67,7 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
* ECMA 15.5 String Objects.
*/
@ScriptClass("String")
public final class NativeString extends ScriptObject {
public final class NativeString extends ScriptObject implements OptimisticBuiltins {
private final CharSequence value;
@ -568,6 +568,14 @@ public final class NativeString extends ScriptObject {
return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
}
private static int getValidChar(final Object self, final int pos) {
try {
return ((CharSequence)self).charAt(pos);
} catch (final IndexOutOfBoundsException e) {
throw new ClassCastException();
}
}
/**
* ECMA 15.5.4.5 String.prototype.charCodeAt (pos)
* @param self self reference
@ -576,7 +584,9 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static double charCodeAt(final Object self, final Object pos) {
return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos));
final String str = checkObjectToString(self);
final int idx = JSType.toInteger(pos);
return idx < 0 || idx >= str.length() ? Double.NaN : str.charAt(idx);
}
/**
@ -585,9 +595,20 @@ public final class NativeString extends ScriptObject {
* @param pos position in string
* @return number representing charcode at position
*/
@SpecializedFunction
public static double charCodeAt(final Object self, final double pos) {
return charCodeAt(self, (int) pos);
@SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
public static int charCodeAt(final Object self, final double pos) {
return charCodeAt(self, (int)pos); //toInt pos is ok
}
/**
* ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for long position
* @param self self reference
* @param pos position in string
* @return number representing charcode at position
*/
@SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
public static int charCodeAt(final Object self, final long pos) {
return charCodeAt(self, (int)pos);
}
/**
@ -596,13 +617,10 @@ public final class NativeString extends ScriptObject {
* @param pos position in string
* @return number representing charcode at position
*/
@SpecializedFunction
public static double charCodeAt(final Object self, final int pos) {
return charCodeAtImpl(checkObjectToString(self), pos);
}
private static double charCodeAtImpl(final String str, final int pos) {
return pos < 0 || pos >= str.length() ? Double.NaN : str.charAt(pos);
@SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
public static int charCodeAt(final Object self, final int pos) {
return getValidChar(self, pos);
}
/**
@ -1097,7 +1115,6 @@ public final class NativeString extends ScriptObject {
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static String trim(final Object self) {
final String str = checkObjectToString(self);
int start = 0;
int end = str.length() - 1;
@ -1181,7 +1198,7 @@ public final class NativeString extends ScriptObject {
*
* @return new NativeString ("")
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self) {
return newObj ? newObj("") : "";
}
@ -1197,7 +1214,7 @@ public final class NativeString extends ScriptObject {
*
* @return new NativeString (arg)
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final Object arg) {
final CharSequence str = JSType.toCharSequence(arg);
return newObj ? newObj(str) : str.toString();
@ -1214,8 +1231,42 @@ public final class NativeString extends ScriptObject {
*
* @return new NativeString containing the string representation of the arg
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final int arg) {
final String str = Integer.toString(arg);
return newObj ? newObj(str) : str;
}
/**
* ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
*
* Constructor
*
* @param newObj is this constructor invoked with the new operator
* @param self self reference
* @param arg the arg
*
* @return new NativeString containing the string representation of the arg
*/
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final long arg) {
final String str = Long.toString(arg);
return newObj ? newObj(str) : str;
}
/**
* ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
*
* Constructor
*
* @param newObj is this constructor invoked with the new operator
* @param self self reference
* @param arg the arg
*
* @return new NativeString containing the string representation of the arg
*/
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final double arg) {
final String str = JSType.toString(arg);
return newObj ? newObj(str) : str;
}
@ -1231,9 +1282,9 @@ public final class NativeString extends ScriptObject {
*
* @return new NativeString containing the string representation of the arg
*/
@SpecializedConstructor
@SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final boolean arg) {
final String str = JSType.toString(arg);
final String str = Boolean.toString(arg);
return newObj ? newObj(str) : str;
}
@ -1281,7 +1332,7 @@ public final class NativeString extends ScriptObject {
} else if (self != null && self == Global.instance().getStringPrototype()) {
return "";
} else {
throw typeError( "not.a.string", ScriptRuntime.safeToString(self));
throw typeError("not.a.string", ScriptRuntime.safeToString(self));
}
}
@ -1310,4 +1361,50 @@ public final class NativeString extends ScriptObject {
return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
}
@Override
public LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
if (clazz == CharCodeAtLinkLogic.class) {
return CharCodeAtLinkLogic.INSTANCE;
}
return null;
}
@Override
public boolean hasPerInstanceAssumptions() {
return false;
}
/**
* This is linker logic charCodeAt - when we specialize further methods in NativeString
* It may be expanded. It's link check makes sure that we are dealing with a char
* sequence and that we are in range
*/
private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic {
private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic();
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
try {
//check that it's a char sequence or throw cce
final CharSequence cs = (CharSequence)self;
//check that the index, representable as an int, is inside the array
final int intIndex = JSType.toInteger(request.getArguments()[1]);
return intIndex >= 0 && intIndex < cs.length(); //can link
} catch (final ClassCastException | IndexOutOfBoundsException e) {
//fallthru
}
return false;
}
/**
* charCodeAt callsites can throw ClassCastException as a mechanism to have them
* relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
* for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
*/
@Override
public Class<? extends Throwable> getRelinkException() {
return ClassCastException.class;
}
}
}

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -118,6 +117,11 @@ public final class NativeUint16Array extends ArrayBufferView {
return true;
}
@Override
public Class<?> getElementType() {
return int.class;
}
@Override
public int getInt(final int index) {
return getElem(index);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -127,6 +126,11 @@ public final class NativeUint32Array extends ArrayBufferView {
return true;
}
@Override
public Class<?> getElementType() {
return int.class;
}
@Override
public int getInt(final int index) {
return (int)getLong(index);

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -118,6 +117,11 @@ public final class NativeUint8Array extends ArrayBufferView {
return true;
}
@Override
public Class<?> getElementType() {
return int.class;
}
@Override
public int getInt(final int index) {
return getElem(index);

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -98,6 +97,11 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
return SET_ELEM;
}
@Override
public Class<?> getElementType() {
return int.class;
}
private int getElem(final int index) {
try {
return nb.get(index) & 0xff;

View File

@ -30,6 +30,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
@ -38,6 +39,7 @@ import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Specialization;
/**
* Concrete implementation of ScriptFunction. This sets correct map for the
@ -58,7 +60,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
// Marker object for lazily initialized prototype object
private static final Object LAZY_PROTOTYPE = new Object();
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs, final Global global) {
super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@ -71,11 +73,11 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param invokeHandle handle for invocation
* @param specs specialized versions of this method, if available, null otherwise
*/
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) {
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
this(name, invokeHandle, specs, Global.instance());
}
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs, final Global global) {
super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@ -89,11 +91,11 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param map initial property map
* @param specs specialized versions of this method, if available, null otherwise
*/
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) {
ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
this(name, invokeHandle, map, specs, Global.instance());
}
private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags, final Global global) {
super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags);
init(global);
}
@ -107,7 +109,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param specs specialized versions of this method, if available, null otherwise
* @param flags {@link ScriptFunctionData} flags
*/
ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) {
ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags) {
this(name, methodHandle, scope, specs, flags, Global.instance());
}
@ -184,7 +186,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
return new AnonymousFunction();
}
private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final int flags) {
private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, flags);
func.setPrototype(UNDEFINED);
// Non-constructor built-in functions do not have "prototype" property
@ -201,7 +203,7 @@ public class ScriptFunctionImpl extends ScriptFunction {
* @param specs specialized versions of function if available, null otherwise
* @return new ScriptFunction
*/
static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
return makeFunction(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,18 +29,315 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.ScriptFunction;
/**
* The SpecializedFunction annotation is used to flag more type specific functions than the standard one in
* Native objects. For example {@link jdk.nashorn.internal.objects.NativeMath#max} takes an arbitrary number of
* Object elements as an array. Call this function, including the varargs collector that allocates the array
* upon each invocation, is much more expensive than calling a specialized function that takes two arguments
* of, e.g. int type from the call site, such as {@link jdk.nashorn.internal.objects.NativeMath#max(Object, int, int)}.
* {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
* linking the callsite.
* The SpecializedFunction annotation is used to flag more type specific
* functions than the standard one in the native objects
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SpecializedFunction {
//empty
/**
* Functionality for testing if we are allowed to link a specialized
* function the first time we encounter it. Then the guard will handle the
* rest of the invocations
*
* This is the same for all callsites in Nashorn, the first time callsite is
* linked, we have to manually check that the linkage is OK. Even if we add
* a guard and it fails upon the first try, this is not good enough.
* (Symmetrical to how it works everywhere else in the Nashorn runtime).
*
* Here we abstract out a few of the most common link guard checks.
*/
public static abstract class LinkLogic {
/**
* Empty link logic instance - this is the default
* "no special linking or runtime guard behavior"
*/
public static final LinkLogic EMPTY_INSTANCE = new Empty();
private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0];
private SwitchPoint[] modificationSwitchPoints; //cache
/** Empty link logic class - allow all linking, no guards */
private static final class Empty extends LinkLogic {
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
return true;
}
@Override
public boolean isEmpty() {
return true;
}
};
/**
* Get the class representing the empty link logic
* @return class representing empty link logic
*/
public static Class<? extends LinkLogic> getEmptyLinkLogicClass() {
return Empty.class;
}
/**
* Should this callsite relink when an exception is thrown
*
* @return the relink exception, or null if none
*/
public Class<? extends Throwable> getRelinkException() {
return null;
}
/**
* Is this link logic class empty - i.e. no special linking logic
* supplied
*
* @param clazz class to check
*
* @return true if this link logic is empty
*/
public static boolean isEmpty(final Class<? extends LinkLogic> clazz) {
return clazz == Empty.class;
}
/**
* Is this link logic instance empty - i.e. no special linking logic
* supplied
*
* @return true if this link logic instance is empty
*/
public boolean isEmpty() {
return false;
}
/**
* Given a callsite, can we link this method based on the receiver and
* parameters?
*
* @param self receiver
* @param desc callsite descriptor
* @param request link request
*
* @return true if we can link this callsite at this time
*/
public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request);
/**
* Given a callsite, do we require an extra guard for specialization to
* go through?
*
* @param self receiver
*
* @return true if a guard is to be woven into the callsite
*/
public boolean needsGuard(final Object self) {
return true;
}
/**
* Given a callsite, and optional arguments, do we need an extra guard
* for specialization to go through - this guard can be a function of
* the arguments too
*
* @param self receiver
* @param args arguments
*
* @return true if a guard is to be woven into the callsite
*/
public boolean needsGuard(final Object self, final Object... args) {
return true;
}
/**
* Given a callsite, and optional arguments, return any extra guard we
* might need for specialization as a method handle.
*
* @return methodhandle for guard, or null if no guard is needed
*/
public MethodHandle getGuard() {
return null;
}
/**
* Return the modification SwitchPoint of a particular index from this OptimisticBuiltins
* If none exists, one is created and that one is return.
*
* The implementor must map indexes to specific SwitchPoints for specific events and keep
* track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT
* might be a useful index mapping
*
* @param index index for SwitchPoint to get or create
* @return modification SwitchPoint of particular index for the receiver
*/
public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
return null;
}
/**
* Return the modification SwitchPoint from this OptimisticBuiltins. If none
* exists, one is created and that one is return.
*
* @return modification SwitchPoint for the receiver
*/
public SwitchPoint[] getOrCreateModificationSwitchPoints() {
return null;
}
/**
* Hook to invalidate a modification SwitchPoint by index.
*
* @param index index for SwitchPoint to invalidate
*/
public void invalidateModificationSwitchPoint(final int index) {
//empty
}
/**
* Hook to invalidate all modification SwitchPoints for a receiver
*/
public void invalidateModificationSwitchPoints() {
//empty
}
/**
* Check whether the receiver has an invalidated modification SwitchPoint.
*
* @param index index for the modification SwitchPoint
* @return true if the particular SwitchPoint at the index is invalidated
*/
public boolean hasInvalidatedModificationSwitchPoint(final int index) {
return false;
}
/**
* Check whether at least one of the modification SwitchPoints has been
* invalidated
* @return true if one of the SwitchPoints has been invalidated
*/
public boolean hasInvalidatedModificationSwitchPoints() {
return false;
}
/**
* Check whether this OptimisticBuiltins has a SwitchPoints of particular
* index.
*
* As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
* e.g. in the constructor of every subclass.
*
* @param index index for the modification SwitchPoint
* @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
*/
public boolean hasModificationSwitchPoint(final int index) {
return false;
}
/**
* Check whether this OptimisticBuiltins has SwitchPoints.
*
* As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
* e.g. in the constructor of every subclass.
*
* @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
*/
public boolean hasModificationSwitchPoints() {
return false;
}
/**
* Check, given a link request and a receiver, if this specialization
* fits This is used by the linker in {@link ScriptFunction} to figure
* out if an optimistic builtin can be linked when first discovered
*
* @param self receiver
* @param desc callsite descriptor
* @param request link request
* @return true if we can link, false otherwise - that means we have to
* pick a non specialized target
*/
public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
// no matter what the modification switchpoints are, if any of them are invalidated,
// we can't link. Side effect is that if it's the first time we see this callsite,
// we have to create the SwitchPoint(s) so future modification switchpoint invalidations
// relink it
final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self);
if (sps == INVALIDATED_SWITCHPOINTS) {
// nope, can't do the fast link as this assumption
// has been invalidated already, e.g. length of an
// array set to not writable
return false;
}
modificationSwitchPoints = sps; //cache
// check the link guard, if it says we can link, go ahead
return canLink(self, desc, request);
}
private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) {
final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints
if (sps != null) { //switchpoint exists, but some may be invalidated
for (final SwitchPoint sp : sps) {
if (sp.hasBeenInvalidated()) {
return INVALIDATED_SWITCHPOINTS;
}
}
}
return sps;
}
/**
* Get the cached modification switchpoints. Only possible to do after a link
* check call has been performed, one that has answered "true", or you will get the
* wrong information.
*
* Should be used only from {@link ScriptFunction#findCallMethod}
*
* @return cached modification switchpoints for this callsite, null if none
*/
public SwitchPoint[] getModificationSwitchPoints() {
return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone();
}
}
/**
* name override for return value polymorphism, for example we can't have
* pop(V)I and pop(V)D in the same Java class, so they need to be named,
* e.g. popInt(V)I and popDouble(V)D for disambiguation, however, their
* names still need to resolve to "pop" to JavaScript so we can still
* specialize on return values and so that the linker can find them
*
* @return name, "" means no override, use the Java function name, e.g.
* "push"
*/
String name() default "";
/**
* Return the guard for this specialized function. The default is no guard.
*
* @return guard
*/
Class<?> linkLogic() default LinkLogic.Empty.class;
/**
* Is this a specialized constructor?
*/
boolean isConstructor() default false;
/**
* Can this function throw UnwarrantedOptimismExceptions? This works just
* like the normal functions, but we need the function to be
* immutable/non-state modifying, as we can't generate continuations for
* native code. Luckily a lot of the methods we want to specialize have this
* property
*/
boolean isOptimistic() default false;
}

View File

@ -36,7 +36,6 @@ import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.JSType.getNumberOfAccessorTypes;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.invoke.MethodHandle;
@ -57,9 +56,7 @@ public class AccessorProperty extends Property {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final MethodHandle REPLACE_MAP = findOwnMH_S("replaceMap", Object.class, Object.class, PropertyMap.class);
private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class);
private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, AccessorProperty.class, Object.class);
private static final int NOOF_TYPES = getNumberOfAccessorTypes();
private static final long serialVersionUID = 3371720170182154920L;
@ -221,7 +218,7 @@ public class AccessorProperty extends Property {
* @param setter the property setter or null if non writable, non configurable
*/
private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
super(key, flags | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
super(key, flags | IS_BUILTIN | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
assert !isSpill();
// we don't need to prep the setters these will never be invalidated as this is a nasgen
@ -602,7 +599,6 @@ public class AccessorProperty extends Property {
private Property getWiderProperty(final Class<?> type) {
return copy(type); //invalidate cache of new property
}
private PropertyMap getWiderMap(final PropertyMap oldMap, final Property newProperty) {
@ -627,8 +623,10 @@ public class AccessorProperty extends Property {
}
@SuppressWarnings("unused")
private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp) {
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
private static Object invalidateSwitchPoint(final AccessorProperty property, final Object obj) {
if (!property.builtinSwitchPoint.hasBeenInvalidated()) {
SwitchPoint.invalidateAll(new SwitchPoint[] { property.builtinSwitchPoint });
}
return obj;
}
@ -668,12 +666,8 @@ public class AccessorProperty extends Property {
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
}
/**
* Check if this is a special global name that requires switchpoint invalidation
*/
final SwitchPoint ccb = getChangeCallback();
if (ccb != null && ccb != NO_CHANGE_CALLBACK) {
mh = MH.filterArguments(mh, 0, MH.insertArguments(debugInvalidate(getKey(), ccb), 1, changeCallback));
if (isBuiltin()) {
mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
}
assert mh.type().returnType() == void.class : mh.type();
@ -681,25 +675,6 @@ public class AccessorProperty extends Property {
return mh;
}
/**
* Get the change callback for this property
* @return switchpoint that is invalidated when property changes
*/
protected SwitchPoint getChangeCallback() {
if (changeCallback == null) {
try {
changeCallback = Global.instance().getChangeCallback(getKey());
} catch (final NullPointerException e) {
assert !"apply".equals(getKey()) && !"call".equals(getKey());
//empty
}
if (changeCallback == null) {
changeCallback = NO_CHANGE_CALLBACK;
}
}
return changeCallback;
}
@Override
public final boolean canChangeType() {
if (OBJECT_FIELDS_ONLY) {
@ -724,7 +699,6 @@ public class AccessorProperty extends Property {
return currentType;
}
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
if (!Context.DEBUG || !Global.hasInstance()) {
return mh;
@ -780,9 +754,9 @@ public class AccessorProperty extends Property {
return mh;
}
private static MethodHandle debugInvalidate(final String key, final SwitchPoint sp) {
private static MethodHandle debugInvalidate(final MethodHandle invalidator, final String key) {
if (!Context.DEBUG || !Global.hasInstance()) {
return INVALIDATE_SP;
return invalidator;
}
final Context context = Context.getContextTrusted();
@ -790,11 +764,11 @@ public class AccessorProperty extends Property {
return context.addLoggingToHandle(
ObjectClassGenerator.class,
INVALIDATE_SP,
invalidator,
new Supplier<String>() {
@Override
public String get() {
return "Field change callback for " + key + " triggered: " + sp;
return "Field change callback for " + key + " triggered ";
}
});
}

View File

@ -81,13 +81,17 @@ public interface CodeInstaller<T> {
/**
* Store a compiled script for later reuse
*
* @param cacheKey key to use in cache
* @param source the script source
* @param mainClassName the main class name
* @param classBytes map of class names to class bytes
* @param initializers compilation id -> FunctionInitializer map
* @param constants constants array
* @param compilationId compilation id
*/
public void storeScript(String cacheKey, Source source, String mainClassName, Map<String, byte[]> classBytes,
Map<Integer, FunctionInitializer> initializers, Object[] constants, int compilationId);
public void storeScript(final String cacheKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes,
final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId);
/**
* Load a previously compiled script

View File

@ -118,6 +118,8 @@ public abstract class CodeStore implements Loggable {
* @param initializers the function initializers
* @param constants the constants array
* @param compilationId the compilation id
*
* @return stored script
*/
public StoredScript store(final String functionKey,
final Source source,
@ -153,11 +155,13 @@ public abstract class CodeStore implements Loggable {
/**
* Returns a new StoredScript instance.
*
* @param source the source
* @param mainClassName the main class name
* @param classBytes a map of class bytes
* @param initializers function initializers
* @param constants the constants array
* @param compilationId the compilation id
*
* @return The compiled script
*/
public StoredScript storedScriptFor(final Source source, final String mainClassName,
@ -216,6 +220,7 @@ public abstract class CodeStore implements Loggable {
* Constructor
*
* @param path directory to store code in
* @param readOnly is this a read only code store
* @param minSize minimum file size for caching scripts
* @throws IOException
*/

View File

@ -33,12 +33,13 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.logging.Level;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@ -46,6 +47,7 @@ import jdk.nashorn.internal.codegen.TypeMap;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.runtime.events.RecompilationEvent;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@ -63,6 +65,8 @@ final class CompiledFunction {
private final DebugLogger log;
static final Collection<CompiledFunction> NO_FUNCTIONS = Collections.emptySet();
/**
* The method type may be more specific than the invoker, if. e.g.
* the invoker is guarded, and a guard with a generic object only
@ -75,20 +79,40 @@ final class CompiledFunction {
private final int flags; // from FunctionNode
private final MethodType callSiteType;
private final Specialization specialization;
CompiledFunction(final MethodHandle invoker) {
this(invoker, null);
this(invoker, null, null);
}
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)));
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker, final Specialization specialization) {
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), specialization);
}
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
this(invoker, constructor, 0, null, DebugLogger.DISABLED_LOGGER);
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final Specialization specialization) {
this(invoker, constructor, 0, null, specialization, DebugLogger.DISABLED_LOGGER);
}
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final DebugLogger log) {
this.invoker = invoker;
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final Specialization specialization, final DebugLogger log) {
this.specialization = specialization;
if (specialization != null && specialization.isOptimistic()) {
/*
* An optimistic builtin with isOptimistic=true works like any optimistic generated function, i.e. it
* can throw unwarranted optimism exceptions. As native functions trivially can't have parts of them
* regenerated as restof methods, this only works if the methods are atomic/functional in their behavior
* and doesn't modify state before an UOE can be thrown. If they aren't, we can reexecute a wider version
* of the same builtin in a recompilation handler for FinalScriptFunctionData. There are several
* candidate methods in Native* that would benefit from this, but I haven't had time to implement any
* of them currently. In order to fit in with the relinking framework, the current thinking is
* that the methods still take a program point to fit in with other optimistic functions, but
* it is set to "first", which is the beginning of the method. The relinker can tell the difference
* between builtin and JavaScript functions. This might change. TODO
*/
this.invoker = MH.insertArguments(invoker, invoker.type().parameterCount() - 1, UnwarrantedOptimismException.FIRST_PROGRAM_POINT);
throw new AssertionError("Optimistic (UnwarrantedOptimismException throwing) builtin functions are currently not in use");
} else {
this.invoker = invoker;
}
this.constructor = constructor;
this.flags = flags;
this.callSiteType = callSiteType;
@ -97,7 +121,7 @@ final class CompiledFunction {
CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData,
final Map<Integer, Type> invalidatedProgramPoints, final MethodType callSiteType, final int flags) {
this(invoker, null, flags, callSiteType, functionData.getLogger());
this(invoker, null, flags, callSiteType, null, functionData.getLogger());
if ((flags & FunctionNode.IS_DEOPTIMIZABLE) != 0) {
optimismInfo = new OptimismInfo(functionData, invalidatedProgramPoints);
} else {
@ -105,10 +129,45 @@ final class CompiledFunction {
}
}
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), null);
}
boolean isSpecialization() {
return specialization != null;
}
boolean hasLinkLogic() {
return getLinkLogicClass() != null;
}
Class<? extends LinkLogic> getLinkLogicClass() {
if (isSpecialization()) {
final Class<? extends LinkLogic> linkLogicClass = specialization.getLinkLogicClass();
assert !LinkLogic.isEmpty(linkLogicClass) : "empty link logic classes should have been removed by nasgen";
return linkLogicClass;
}
return null;
}
int getFlags() {
return flags;
}
/**
* An optimistic specialization is one that can throw UnwarrantedOptimismException.
* This is allowed for native methods, as long as they are functional, i.e. don't change
* any state between entering and throwing the UOE. Then we can re-execute a wider version
* of the method in the continuation. Rest-of method generation for optimistic builtins is
* of course not possible, but this approach works and fits into the same relinking
* framework
*
* @return true if optimistic builtin
*/
boolean isOptimistic() {
return isSpecialization() ? specialization.isOptimistic() : false;
}
boolean isApplyToCall() {
return (flags & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0;
}
@ -119,7 +178,19 @@ final class CompiledFunction {
@Override
public String toString() {
return "[invokerType=" + invoker.type() + " ctor=" + constructor + " weight=" + weight() + " isApplyToCall=" + isApplyToCall() + "]";
final StringBuilder sb = new StringBuilder();
final Class<? extends LinkLogic> linkLogicClass = getLinkLogicClass();
sb.append("[invokerType=").
append(invoker.type()).
append(" ctor=").
append(constructor).
append(" weight=").
append(weight()).
append(" linkLogic=").
append(linkLogicClass != null ? linkLogicClass.getSimpleName() : "none");
return sb.toString();
}
boolean needsCallee() {
@ -281,10 +352,12 @@ final class CompiledFunction {
if (other == null) {
return true;
}
return betterThanFinal(type(), other.type(), callSiteMethodType);
return betterThanFinal(this, other, callSiteMethodType);
}
static boolean betterThanFinal(final MethodType thisMethodType, final MethodType otherMethodType, final MethodType callSiteMethodType) {
private static boolean betterThanFinal(final CompiledFunction cf, final CompiledFunction other, final MethodType callSiteMethodType) {
final MethodType thisMethodType = cf.type();
final MethodType otherMethodType = other.type();
final int thisParamCount = getParamCount(thisMethodType);
final int otherParamCount = getParamCount(otherMethodType);
final int callSiteRawParamCount = getParamCount(callSiteMethodType);
@ -406,7 +479,17 @@ final class CompiledFunction {
return false;
}
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical
//if they are equal, pick the specialized one first
if (cf.isSpecialization() != other.isSpecialization()) {
return cf.isSpecialization(); //always pick the specialized version if we can
}
if (cf.isSpecialization() && other.isSpecialization()) {
return cf.getLinkLogicClass() != null; //pick link logic specialization above generic specializations
}
// Signatures are identical
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType);
}
private static Type[] toTypeWithoutCallee(final MethodType type, final int thisIndex) {

View File

@ -40,6 +40,7 @@ import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
@ -63,7 +64,9 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
import javax.script.ScriptEngine;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.api.scripting.ClassFilter;
@ -127,6 +130,16 @@ public final class Context {
private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
/**
* Keeps track of which builtin prototypes and properties have been relinked
* Currently we are conservative and associate the name of a builtin class with all
* its properties, so it's enough to invalidate a property to break all assumptions
* about a prototype. This can be changed to a more fine grained approach, but no one
* ever needs this, given the very rare occurance of swapping out only parts of
* a builtin v.s. the entire builtin object
*/
private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
/* Force DebuggerSupport to be loaded. */
static {
DebuggerSupport.FORCELOAD = true;
@ -1371,4 +1384,34 @@ public final class Context {
return null;
}
/**
* This is a special kind of switchpoint used to guard builtin
* properties and prototypes. In the future it might contain
* logic to e.g. multiple switchpoint classes.
*/
public static final class BuiltinSwitchPoint extends SwitchPoint {
}
/**
* Create a new builtin switchpoint and return it
* @param name key name
* @return new builtin switchpoint
*/
public SwitchPoint newBuiltinSwitchPoint(final String name) {
assert builtinSwitchPoints.get(name) == null;
final SwitchPoint sp = new BuiltinSwitchPoint();
builtinSwitchPoints.put(name, sp);
return sp;
}
/**
* Return the builtin switchpoint for a particular key name
* @param name key name
* @return builtin switchpoint or null if none
*/
public SwitchPoint getBuiltinSwitchPoint(final String name) {
return builtinSwitchPoints.get(name);
}
}

View File

@ -60,13 +60,13 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
* @param specs specializations
* @param flags {@link ScriptFunctionData} flags
*/
FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
FinalScriptFunctionData(final String name, final MethodHandle mh, final Specialization[] specs, final int flags) {
super(name, methodHandleArity(mh), flags);
addInvoker(mh);
if (specs != null) {
for (final MethodHandle spec : specs) {
addInvoker(spec);
for (final Specialization spec : specs) {
addInvoker(spec.getMethodHandle(), spec);
}
}
}
@ -114,16 +114,25 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
return MethodType.genericMethodType(max + 1);
}
private void addInvoker(final MethodHandle mh) {
private CompiledFunction addInvoker(final MethodHandle mh, final Specialization specialization) {
assert !needsCallee(mh);
final CompiledFunction invoker;
if (isConstructor(mh)) {
// only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
// is too conservative a check. However, isConstructor(mh) always implies isConstructor param
assert isConstructor();
code.add(CompiledFunction.createBuiltInConstructor(mh));
invoker = CompiledFunction.createBuiltInConstructor(mh);
} else {
code.add(new CompiledFunction(mh));
invoker = new CompiledFunction(mh, null, specialization);
}
code.add(invoker);
return invoker;
}
private CompiledFunction addInvoker(final MethodHandle mh) {
return addInvoker(mh, null);
}
private static int methodHandleArity(final MethodHandle mh) {

View File

@ -79,6 +79,8 @@ public final class FindProperty {
*
* @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
* @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
* @param request link request
*
* @return method handle for the getter
*/
public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
@ -102,6 +104,7 @@ public final class FindProperty {
*
* @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
* @param strict are we in strict mode
* @param request link request
*
* @return method handle for the getter
*/

View File

@ -358,8 +358,12 @@ public final class GlobalConstants implements Loggable {
* @param c constant value
* @return method handle (with dummy receiver) that returns this constant
*/
public static MethodHandle staticConstantGetter(final Object c) {
return MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
}
private MethodHandle constantGetter(final Object c) {
final MethodHandle mh = MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
final MethodHandle mh = staticConstantGetter(c);
if (log.isEnabled()) {
return MethodHandleFactory.addDebugPrintout(log, Level.FINEST, mh, "getting as constant");
}

View File

@ -42,12 +42,30 @@ public final class GlobalFunctions {
/** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class);
/** ParseInt - NaN for booleans (thru string conversion to number conversion) */
public static final MethodHandle PARSEINT_Z = MH.dropArguments(MH.dropArguments(MH.constant(double.class, Double.NaN), 0, boolean.class), 0, Object.class);
/** ParseInt - identity for ints */
public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class);
/** ParseInt - identity for longs */
public static final MethodHandle PARSEINT_J = MH.dropArguments(MH.identity(long.class), 0, Object.class);
/** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
/** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */
public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class);
/** isNan for integers - always false */
public static final MethodHandle IS_NAN_I = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
/** isNan for longs - always false */
public static final MethodHandle IS_NAN_J = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
/** IsNan for doubles - use Double.isNaN */
public static final MethodHandle IS_NAN_D = MH.dropArguments(MH.findStatic(MethodHandles.lookup(), Double.class, "isNaN", MH.type(boolean.class, double.class)), 0, Object.class);
/** Methodhandle to implementation of ECMA 15.1.2.4, isNaN */
public static final MethodHandle IS_NAN = findOwnMH("isNaN", boolean.class, Object.class, Object.class);

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
/**
* This is an interface for classes that need custom linkage logic. This means Native objects
* that contain optimistic native methods, that need special/extra rules for linking, guards and
* SwitchPointing, known and internal to the Native object for its linkage
*/
public interface OptimisticBuiltins {
/**
* Return an instance of the linking logic we need for a particular LinkLogic
* subclass, gotten from the compile time annotation of a specialized builtin method
* No assumptions can be made about the lifetime of the instance. The receiver may
* keep it as a perpetual final instance field or create new linking logic depending
* on its current state for each call, depending on if the global state has changed
* or other factors
*
* @param clazz linking logic class
* @return linking logic instance for this class
*/
public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz);
/**
* Does this link logic vary depending on which instance we are working with.
* Then we have to sort out certain primitives, as they are created as new
* objects in the wrapFilter by JavaScript semantics. An example of instance only
* assumptions are switchPoints per instance, as in NativeArray. NativeString is
* fine, as it's only static.
*
* TODO: finer granularity on this, on the function level so certain functions
* are forbidden only. Currently we don't have enough specialization to bump into this
*
* @return true if there are per instance assumptions for the optimism
*/
public boolean hasPerInstanceAssumptions();
}

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
@ -84,6 +83,9 @@ public abstract class Property implements Serializable {
*/
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
/** Is this a builtin property, e.g. Function.prototype.apply */
public static final int IS_BUILTIN = 1 << 7;
/** Is this property bound to a receiver? This means get/set operations will be delegated to
* a statically defined object instead of the object passed as callsite parameter. */
public static final int IS_BOUND = 1 << 7;
@ -101,7 +103,7 @@ public abstract class Property implements Serializable {
private final int slot;
/** SwitchPoint that is invalidated when property is changed, optional */
protected transient SwitchPoint changeCallback;
protected transient SwitchPoint builtinSwitchPoint;
private static final long serialVersionUID = 2099814273074501176L;
@ -125,10 +127,10 @@ public abstract class Property implements Serializable {
* @param property source property
*/
Property(final Property property, final int flags) {
this.key = property.key;
this.slot = property.slot;
this.changeCallback = property.changeCallback;
this.flags = flags;
this.key = property.key;
this.slot = property.slot;
this.builtinSwitchPoint = property.builtinSwitchPoint;
this.flags = flags;
}
/**
@ -182,8 +184,26 @@ public abstract class Property implements Serializable {
* changed
* @param sp SwitchPoint to use for change callback
*/
public final void setChangeCallback(final SwitchPoint sp) {
this.changeCallback = sp;
public final void setBuiltinSwitchPoint(final SwitchPoint sp) {
this.builtinSwitchPoint = sp;
}
/**
* Builtin properties have an invalidation switchpoint that is
* invalidated when they are set, this is a getter for it
* @return builtin switchpoint, or null if none
*/
public final SwitchPoint getBuiltinSwitchPoint() {
return builtinSwitchPoint;
}
/**
* Checks if this is a builtin property, this means that it has
* a builtin switchpoint that hasn't been invalidated by a setter
* @return true if builtin, untouched (unset) property
*/
public boolean isBuiltin() {
return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated();
}
/**

View File

@ -950,7 +950,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
@Override
public void remove() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("remove");
}
}

View File

@ -26,11 +26,11 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -454,7 +454,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
// CompilationEnvironment#declareLocalSymbol()).
if (log.isEnabled()) {
log.info("Type specialization of '", functionName, "' signature: ", actualCallSiteType);
log.info("Parameter type specialization of '", functionName, "' signature: ", actualCallSiteType);
}
final boolean persistentCache = usePersistentCodeCache() && persist;
@ -597,6 +597,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
* Initializes this function data with the eagerly generated version of the code. This method can only be invoked
* by the compiler internals in Nashorn and is public for implementation reasons only. Attempting to invoke it
* externally will result in an exception.
*
* @param initializer FunctionInitializer for this data
*/
public void initializeCode(final FunctionInitializer initializer) {
// Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit.
@ -658,8 +660,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
@Override
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
if (existingBest == null) {
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
}
@ -723,6 +725,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return functionNodeId;
}
/**
* Get the source for the script
* @return source
*/
public Source getSource() {
return source;
}

View File

@ -181,9 +181,6 @@ public final class ScriptEnvironment {
/** print symbols and their contents for the script */
public final boolean _print_symbols;
/** range analysis for known types */
public final boolean _range_analysis;
/** is this environment in scripting mode? */
public final boolean _scripting;
@ -255,7 +252,6 @@ public final class ScriptEnvironment {
_print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse");
_print_symbols = options.getBoolean("print.symbols");
_range_analysis = options.getBoolean("range.analysis");
_scripting = options.getBoolean("scripting");
_strict = options.getBoolean("strict");
_version = options.getBoolean("version");

View File

@ -30,26 +30,29 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.objects.NativeFunction;
import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
/**
* Runtime representation of a JavaScript function.
@ -114,7 +117,7 @@ public abstract class ScriptFunction extends ScriptObject {
final MethodHandle methodHandle,
final PropertyMap map,
final ScriptObject scope,
final MethodHandle[] specs,
final Specialization[] specs,
final int flags) {
this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
@ -468,13 +471,12 @@ public abstract class ScriptFunction extends ScriptObject {
protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType type = desc.getMethodType();
assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
final CompiledFunction cf = data.getBestConstructor(type, scope);
final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
//TODO - ClassCastException
return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
}
@SuppressWarnings("unused")
private static Object wrapFilter(final Object obj) {
if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
return obj;
@ -489,6 +491,35 @@ public abstract class ScriptFunction extends ScriptObject {
return Context.getGlobal();
}
/**
* Some receivers are primitive, in that case, according to the Spec we create a new
* native object per callsite with the wrap filter. We can only apply optimistic builtins
* if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings),
* otherwise we can't create optimistic versions
*
* @param self receiver
* @param linkLogicClass linkLogicClass, or null if no link logic exists
* @return link logic instance, or null if one could not be constructed for this receiver
*/
private LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
if (linkLogicClass == null) {
return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
}
if (!Context.getContextTrusted().getEnv()._optimistic_types) {
return null; //if optimistic types are off, optimistic builtins are too
}
final Object wrappedSelf = wrapFilter(self);
if (wrappedSelf instanceof OptimisticBuiltins) {
if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) {
return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
}
return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass);
}
return null;
}
/**
* dyn:call call site signature: (callee, thiz, [args...])
* generated method signature: (callee, thiz, [args...])
@ -547,8 +578,53 @@ public abstract class ScriptFunction extends ScriptObject {
}
} //else just fall through and link as ordinary function or unstable apply
final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
final CompiledFunction cf = data.getBestInvoker(type, scope);
int programPoint = INVALID_PROGRAM_POINT;
if (NashornCallSiteDescriptor.isOptimistic(desc)) {
programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
}
CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
final Object self = request.getArguments()[1];
final Collection<CompiledFunction> forbidden = new HashSet<>();
//check for special fast versions of the compiled function
final List<SwitchPoint> sps = new ArrayList<>();
Class<? extends Throwable> exceptionGuard = null;
while (cf.isSpecialization()) {
final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
//if linklogic is null, we can always link with the standard mechanism, it's still a specialization
final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
if (log.isEnabled()) {
log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
}
final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
if (msps != null) {
for (final SwitchPoint sp : msps) {
if (sp != null) {
assert !sp.hasBeenInvalidated();
sps.add(sp);
}
}
}
exceptionGuard = linkLogic.getRelinkException();
break;
}
//could not link this specialization because link check failed
forbidden.add(cf);
final CompiledFunction oldCf = cf;
cf = data.getBestInvoker(type, scope, forbidden);
assert oldCf != cf;
}
final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
final MethodHandle callHandle = bestInvoker.getInvocation();
@ -588,7 +664,20 @@ public abstract class ScriptFunction extends ScriptObject {
boundHandle = pairArguments(boundHandle, type);
return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this, cf.getFlags()) : guard, bestInvoker.getSwitchPoints(), null);
if (bestInvoker.getSwitchPoints() != null) {
sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
}
final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
return new GuardedInvocation(
boundHandle,
guard == null ?
getFunctionGuard(
this,
cf.getFlags()) :
guard,
spsArray,
exceptionGuard);
}
private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
@ -610,7 +699,7 @@ public abstract class ScriptFunction extends ScriptObject {
//box call back to apply
CallSiteDescriptor appliedDesc = desc;
final SwitchPoint applyToCallSwitchPoint = Global.instance().getChangeCallback("apply");
final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
//enough to change the proto switchPoint here
final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
@ -656,7 +745,7 @@ public abstract class ScriptFunction extends ScriptObject {
}
}
appliedDesc = appliedDesc.changeMethodType(appliedType);
appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
// Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
@ -681,6 +770,7 @@ public abstract class ScriptFunction extends ScriptObject {
// Ask the linker machinery for an invocation of the target function
final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
GuardedInvocation appliedInvocation;
try {
appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
@ -742,7 +832,7 @@ public abstract class ScriptFunction extends ScriptObject {
// We need to account for the dropped (apply|call) function argument.
guard = MH.dropArguments(guard, 0, descType.parameterType(0));
// Take the "isApplyFunction" guard, and bind it to this function.
MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this);
MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
// Adapt the guard to receive all the arguments that the original guard does.
applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
// Fold the original function guard into our apply guard.
@ -894,6 +984,7 @@ public abstract class ScriptFunction extends ScriptObject {
return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
}
//TODO this can probably be removed given that we have builtin switchpoints in the context
@SuppressWarnings("unused")
private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
// NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()

View File

@ -28,13 +28,13 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@ -136,7 +136,7 @@ public abstract class ScriptFunctionData implements Serializable {
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
if (isConstructor()) {
return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args));
return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args), null);
}
return new CompiledFunction(boundInvoker);
@ -224,18 +224,22 @@ public abstract class ScriptFunctionData implements Serializable {
* @param callSiteType callsite type
* @return compiled function object representing the best invoker.
*/
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
final CompiledFunction cf = getBest(callSiteType, runtimeScope);
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
return getBestInvoker(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS);
}
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
final CompiledFunction cf = getBest(callSiteType, runtimeScope, forbidden);
assert cf != null;
return cf;
}
final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
if (!isConstructor()) {
throw typeError("not.a.constructor", toSource());
}
// Constructor call sites don't have a "this", but getBest is meant to operate on "callee, this, ..." style
final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope);
final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope, forbidden);
return cf;
}
@ -350,7 +354,7 @@ public abstract class ScriptFunctionData implements Serializable {
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
* @return the best function for the specified call site type.
*/
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
@ -363,8 +367,8 @@ public abstract class ScriptFunctionData implements Serializable {
}
CompiledFunction best = null;
for(final CompiledFunction candidate: code) {
if(candidate.betterThanFinal(best, callSiteType)) {
for (final CompiledFunction candidate: code) {
if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
best = candidate;
}
}
@ -376,7 +380,7 @@ public abstract class ScriptFunctionData implements Serializable {
abstract boolean isRecompilable();
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
return getBest(getGenericType(), runtimeScope);
return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
}
/**
@ -420,7 +424,7 @@ public abstract class ScriptFunctionData implements Serializable {
final List<CompiledFunction> boundList = new LinkedList<>();
final ScriptObject runtimeScope = fn.getScope();
final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope));
final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope), null);
boundList.add(bind(bindTarget, fn, self, allArgs));
return new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, boundFlags);

View File

@ -47,7 +47,6 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -820,6 +819,19 @@ public abstract class ScriptObject implements PropertyAccess {
return false;
}
private SwitchPoint findBuiltinSwitchPoint(final String key) {
for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
final Property prop = myProto.getMap().findProperty(key);
if (prop != null) {
final SwitchPoint sp = prop.getBuiltinSwitchPoint();
if (sp != null && !sp.hasBeenInvalidated()) {
return sp;
}
}
}
return null;
}
/**
* Add a new property to the object.
* <p>
@ -1513,6 +1525,23 @@ public abstract class ScriptObject implements PropertyAccess {
flags |= IS_LENGTH_NOT_WRITABLE;
}
/**
* Get the {@link ArrayData}, for this ScriptObject, ensuring it is of a type
* that can handle elementType
* @param elementType elementType
* @return array data
*/
public final ArrayData getArray(final Class<?> elementType) {
if (elementType == null) {
return arrayData;
}
final ArrayData newArrayData = arrayData.convert(elementType);
if (newArrayData != arrayData) {
arrayData = newArrayData;
}
return newArrayData;
}
/**
* Get the {@link ArrayData} for this ScriptObject if it is an array
* @return array data
@ -1916,17 +1945,6 @@ public abstract class ScriptObject implements PropertyAccess {
return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
}
//this will only return true if apply is still builtin
private static SwitchPoint checkReservedName(final CallSiteDescriptor desc, final LinkRequest request) {
final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
if ("apply".equals(name) && isApplyToCall && Global.instance().isSpecialNameValid(name)) {
assert Global.instance().getChangeCallback("apply") == Global.instance().getChangeCallback("call");
return Global.instance().getChangeCallback("apply");
}
return null;
}
/**
* Find the appropriate GET method for an invoke dynamic call.
*
@ -1938,14 +1956,13 @@ public abstract class ScriptObject implements PropertyAccess {
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
final String name;
final SwitchPoint reservedNameSwitchPoint;
reservedNameSwitchPoint = checkReservedName(desc, request);
if (reservedNameSwitchPoint != null) {
name = "call"; //turn apply into call, it is the builtin apply and has been modified to explode args
} else {
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
String name;
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
if (Global.isBuiltinFunctionPrototypeApply()) {
name = "call";
}
}
if (request.isCallSiteUnstable() || hasWithScope()) {
@ -2006,7 +2023,7 @@ public abstract class ScriptObject implements PropertyAccess {
assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
return inv.addSwitchPoint(reservedNameSwitchPoint);
return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
@ -2166,7 +2183,7 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
if (cinv != null) {
@ -2429,7 +2446,7 @@ public abstract class ScriptObject implements PropertyAccess {
@Override
public void remove() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("remove");
}
}

View File

@ -32,9 +32,9 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.Iterator;
@ -46,6 +46,7 @@ import java.util.Objects;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.ir.debug.JSONWriter;
@ -112,6 +113,11 @@ public final class ScriptRuntime {
*/
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
/**
* Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
*/
public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class);
/**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
@ -290,7 +296,7 @@ public final class ScriptRuntime {
@Override
public void remove() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("remove");
}
}
@ -328,7 +334,7 @@ public final class ScriptRuntime {
@Override
public void remove() {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("remove");
}
};
}
@ -998,4 +1004,19 @@ public final class ScriptRuntime {
return nx < ny;
}
/**
* Tag a reserved name as invalidated - used when someone writes
* to a property with this name - overly conservative, but link time
* is too late to apply e.g. apply-&gt;call specialization
* @param name property name
*/
public static void invalidateReservedBuiltinName(final String name) {
final Context context = Context.getContextTrusted();
final SwitchPoint sp = context.getBuiltinSwitchPoint(name);
assert sp != null;
if (sp != null) {
context.getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
}
}
}

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
@ -81,8 +80,8 @@ final class SetMethodCreator {
* Creates the actual guarded invocation that represents the dynamic setter method for the property.
* @return the actual guarded invocation that represents the dynamic setter method for the property.
*/
GuardedInvocation createGuardedInvocation() {
return createSetMethod().createGuardedInvocation();
GuardedInvocation createGuardedInvocation(final SwitchPoint builtinSwitchPoint) {
return createSetMethod(builtinSwitchPoint).createGuardedInvocation();
}
/**
@ -119,7 +118,7 @@ final class SetMethodCreator {
}
}
private SetMethod createSetMethod() {
private SetMethod createSetMethod(final SwitchPoint builtinSwitchPoint) {
if (find != null) {
return createExistingPropertySetter();
}
@ -130,7 +129,7 @@ final class SetMethodCreator {
return createGlobalPropertySetter();
}
return createNewPropertySetter();
return createNewPropertySetter(builtinSwitchPoint);
}
private void checkStrictCreateNewVariable() {
@ -185,8 +184,8 @@ final class SetMethodCreator {
return new SetMethod(MH.filterArguments(global.addSpill(type, getName()), 0, ScriptObject.GLOBALFILTER), null);
}
private SetMethod createNewPropertySetter() {
final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter() : createNewSpillPropertySetter();
private SetMethod createNewPropertySetter(final SwitchPoint builtinSwitchPoint) {
final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter(builtinSwitchPoint) : createNewSpillPropertySetter(builtinSwitchPoint);
final PropertyListeners listeners = map.getListeners();
if (listeners != null) {
listeners.propertyAdded(sm.property);
@ -194,7 +193,9 @@ final class SetMethodCreator {
return sm;
}
private SetMethod createNewSetter(final Property property) {
private SetMethod createNewSetter(final Property property, final SwitchPoint builtinSwitchPoint) {
property.setBuiltinSwitchPoint(builtinSwitchPoint);
final PropertyMap oldMap = getMap();
final PropertyMap newMap = getNewMap(property);
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
@ -230,12 +231,12 @@ final class SetMethodCreator {
return new SetMethod(MH.asType(MH.guardWithTest(extCheck, casGuard, nop), fastSetter.type()), property);
}
private SetMethod createNewFieldSetter() {
return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type));
private SetMethod createNewFieldSetter(final SwitchPoint builtinSwitchPoint) {
return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
}
private SetMethod createNewSpillPropertySetter() {
return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type));
private SetMethod createNewSpillPropertySetter(final SwitchPoint builtinSwitchPoint) {
return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
}
private PropertyMap getNewMap(final Property property) {

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
/**
* Specialization info for a {@link SpecializedFunction}
*/
public final class Specialization {
private final MethodHandle mh;
private final Class<? extends LinkLogic> linkLogicClass;
private final boolean isOptimistic;
/**
* Constructor
*
* @param mh invoker method handler
*/
public Specialization(final MethodHandle mh) {
this(mh, false);
}
/**
* Constructor
*
* @param mh invoker method handler
* @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
* which would have to lead to a relink and return value processing
*/
public Specialization(final MethodHandle mh, final boolean isOptimistic) {
this(mh, null, isOptimistic);
}
/**
* Constructor
*
* @param mh invoker method handler
* @param linkLogicClass extra link logic needed for this function. Instances of this class also contains logic for checking
* if this can be linked on its first encounter, which is needed as per our standard linker semantics
* @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
* which would have to lead to a relink and return value processing
*/
public Specialization(final MethodHandle mh, final Class<? extends LinkLogic> linkLogicClass, final boolean isOptimistic) {
this.mh = mh;
this.isOptimistic = isOptimistic;
if (linkLogicClass != null) {
//null out the "empty" link logic class for optimization purposes
//we only use the empty instance because we can't default class annotations
//to null
this.linkLogicClass = LinkLogic.isEmpty(linkLogicClass) ? null : linkLogicClass;
} else {
this.linkLogicClass = null;
}
}
/**
* Get the method handle for the invoker of this ScriptFunction
* @return the method handle
*/
public MethodHandle getMethodHandle() {
return mh;
}
/**
* Get the link logic class for this ScriptFunction
* @return link logic class info, i.e. one whose instance contains stuff like
* "do we need exception check for every call", and logic to check if we may link
*/
public Class<? extends LinkLogic> getLinkLogicClass() {
return linkLogicClass;
}
/**
* An optimistic specialization is one that can throw UnwarrantedOptimismException.
* This is allowed for native methods, as long as they are functional, i.e. don't change
* any state between entering and throwing the UOE. Then we can re-execute a wider version
* of the method in the continuation. Rest-of method generation for optimistic builtins is
* of course not possible, but this approach works and fits into the same relinking
* framework
*
* @return true if optimistic
*/
public boolean isOptimistic() {
return isOptimistic;
}
}

View File

@ -55,8 +55,10 @@ public final class StoredScript implements Serializable {
/**
* Constructor.
*
* @param compilationId compilation id
* @param mainClassName main class name
* @param classBytes map of class names to class bytes
* @param initializers initializer map, id -> FunctionInitializer
* @param constants constants array
*/
public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
@ -67,6 +69,10 @@ public final class StoredScript implements Serializable {
this.initializers = initializers;
}
/**
* Get the compilation id for this StoredScript
* @return compilation id
*/
public int getCompilationId() {
return compilationId;
}

View File

@ -25,7 +25,6 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC;

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@ -58,7 +57,7 @@ public abstract class ArrayData {
/**
* Length of the array data. Not necessarily length of the wrapped array.
*/
private long length;
protected long length;
/**
* Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
@ -520,7 +519,7 @@ public abstract class ArrayData {
* @param type new element type
* @return new array data
*/
protected abstract ArrayData convert(Class<?> type);
public abstract ArrayData convert(Class<?> type);
/**
* Push an array of items to the end of the array
@ -655,7 +654,7 @@ public abstract class ArrayData {
* @param size current size
* @return next size to allocate for internal array
*/
protected static int nextSize(final int size) {
public static int nextSize(final int size) {
return alignUp(size + 1) * 2;
}
@ -681,6 +680,18 @@ public abstract class ArrayData {
}
}
/**
* Find a fast call if one exists
*
* @param clazz array data class
* @param desc callsite descriptor
* @param request link request
* @return fast property getter if one is found
*/
public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
return null;
}
/**
* Find a fast property getter if one exists
*

View File

@ -201,7 +201,7 @@ abstract class ArrayFilter extends ArrayData {
}
@Override
protected ArrayData convert(final Class<?> type) {
public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
setLength(underlying.length());
return this;

View File

@ -30,7 +30,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -115,6 +114,12 @@ public abstract class ContinuousArrayData extends ArrayData {
return index;
}
/**
* Returns the type used to store an element in this array
* @return element type
*/
public abstract Class<?> getElementType();
/**
* Look up a continuous array element getter
* @param get getter, sometimes combined with a has check that throws CCE on failure for relink
@ -175,11 +180,6 @@ public abstract class ContinuousArrayData extends ArrayData {
return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz));
}
@Override
public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
return null;
}
/** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need
the null case explicitly, which is the one that CCE doesn't handle */
protected static final MethodHandle FAST_ACCESS_GUARD =
@ -269,4 +269,72 @@ public abstract class ContinuousArrayData extends ArrayData {
return null;
}
/**
* Specialization - fast push implementation
* @param arg argument
* @return new array length
*/
public long fastPush(final int arg) {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast push implementation
* @param arg argument
* @return new array length
*/
public long fastPush(final long arg) {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast push implementation
* @param arg argument
* @return new array length
*/
public long fastPush(final double arg) {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast push implementation
* @param arg argument
* @return new array length
*/
public long fastPush(final Object arg) {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast pop implementation
* @return element value
*/
public int fastPopInt() {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast pop implementation
* @return element value
*/
public long fastPopLong() {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast pop implementation
* @return element value
*/
public double fastPopDouble() {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
/**
* Specialization - fast pop implementation
* @return element value
*/
public Object fastPopObject() {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
}

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -38,7 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Implementation of {@link ArrayData} as soon as an int has been
* written to the array. This is the default data for new arrays
*/
final class IntArrayData extends ContinuousArrayData {
final class IntArrayData extends ContinuousArrayData implements IntElements {
/**
* The wrapped array
*/
@ -64,9 +63,19 @@ final class IntArrayData extends ContinuousArrayData {
this.array = array;
}
@Override
public Class<?> getElementType() {
return int.class;
}
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
@Override
public Object[] asObjectArray() {
return toObjectArray();
}
@SuppressWarnings("unused")
private int getElem(final int index) {
if (has(index)) {
@ -99,11 +108,6 @@ final class IntArrayData extends ContinuousArrayData {
return new IntArrayData(array.clone(), (int) length());
}
@Override
public Object[] asObjectArray() {
return toObjectArray(array, (int) length());
}
@Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == int.class) {
@ -112,7 +116,7 @@ final class IntArrayData extends ContinuousArrayData {
return super.asArrayOfType(componentType);
}
private static Object[] toObjectArray(final int[] array, final int length) {
private Object[] toObjectArray() {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[array.length];
@ -123,7 +127,7 @@ final class IntArrayData extends ContinuousArrayData {
return oarray;
}
private static double[] toDoubleArray(final int[] array, final int length) {
private double[] toDoubleArray() {
assert length <= array.length : "length exceeds internal array size";
final double[] darray = new double[array.length];
@ -134,7 +138,7 @@ final class IntArrayData extends ContinuousArrayData {
return darray;
}
private static long[] toLongArray(final int[] array, final int length) {
private long[] toLongArray() {
assert length <= array.length : "length exceeds internal array size";
final long[] larray = new long[array.length];
@ -145,18 +149,30 @@ final class IntArrayData extends ContinuousArrayData {
return larray;
}
private LongArrayData convertToLong() {
return new LongArrayData(toLongArray(), (int)length);
}
private NumberArrayData convertToDouble() {
return new NumberArrayData(toDoubleArray(), (int)length);
}
private ObjectArrayData convertToObject() {
return new ObjectArrayData(toObjectArray(), (int)length);
}
@Override
public ArrayData convert(final Class<?> type) {
if (type == Integer.class) {
return this;
}
final int length = (int) length();
if (type == Long.class) {
return new LongArrayData(IntArrayData.toLongArray(array, length), length);
return convertToLong();
} else if (type == Double.class) {
return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length);
return convertToDouble();
} else {
return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length);
assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive());
return convertToObject();
}
}
@ -355,4 +371,41 @@ final class IntArrayData extends ContinuousArrayData {
return returnValue;
}
@Override
public long fastPush(final int arg) {
final int len = (int)length;
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
}
//length must not be zero
@Override
public int fastPopInt() {
if (length == 0) {
throw new ClassCastException(); //relink
}
final int newLength = (int)--length;
final int elem = array[newLength];
array[newLength] = 0;
return elem;
}
@Override
public long fastPopLong() {
return fastPopInt();
}
@Override
public double fastPopDouble() {
return fastPopInt();
}
@Override
public Object fastPopObject() {
return fastPopInt();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2014, 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
@ -22,26 +22,13 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.objects.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
package jdk.nashorn.internal.runtime.arrays;
/**
* The SpecializedConstructor annotation is used to flag more type specific constructors than the standard one in
* Native objects. For example {@link jdk.nashorn.internal.objects.NativeArray#construct} takes an arbitrary number of
* Object elements as an array. Call this constructor, including the varargs collector that allocates the array
* upon each invocation, is much more expensive than calling a specialized constructor that takes one arguments
* of, e.g. int type from the call site, such as
* {@link jdk.nashorn.internal.objects.NativeArray#construct(boolean, Object, int)}.
* {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
* linking the callsite.
* Marker interface for any ContinuousArray with int elements
* Used for type checks that throw ClassCastExceptions and force relinks
* for fast NativeArray specializations of builtin methods
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SpecializedConstructor {
public interface IntElements extends IntOrLongElements {
//empty
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
/**
* Marker interface for any ContinuousArray with int or long elements
* Used for type checks that throw ClassCastExceptions and force relinks
* for fast NativeArray specializations of builtin methods
*/
public interface IntOrLongElements extends NumericElements {
//empty
}

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -39,7 +38,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Implementation of {@link ArrayData} as soon as a long has been
* written to the array
*/
final class LongArrayData extends ContinuousArrayData {
final class LongArrayData extends ContinuousArrayData implements IntOrLongElements {
/**
* The wrapped array
*/
@ -56,6 +55,11 @@ final class LongArrayData extends ContinuousArrayData {
this.array = array;
}
@Override
public Class<?> getElementType() {
return long.class;
}
@Override
public ArrayData copy() {
return new LongArrayData(array.clone(), (int)length());
@ -324,4 +328,41 @@ final class LongArrayData extends ContinuousArrayData {
return returnValue;
}
@Override
public long fastPush(final int arg) {
return fastPush((long)arg);
}
@Override
public long fastPush(final long arg) {
final int len = (int)length;
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
}
@Override
public long fastPopLong() {
if (length == 0) {
throw new ClassCastException();
}
final int newLength = (int)--length;
final long elem = array[newLength];
array[newLength] = 0;
return elem;
//return array[(int)--length];
}
@Override
public double fastPopDouble() {
return fastPopLong();
}
@Override
public Object fastPopObject() {
return fastPopLong();
}
}

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -38,7 +37,7 @@ import jdk.nashorn.internal.codegen.types.Type;
* Implementation of {@link ArrayData} as soon as a double has been
* written to the array
*/
final class NumberArrayData extends ContinuousArrayData {
final class NumberArrayData extends ContinuousArrayData implements NumericElements {
/**
* The wrapped array
*/
@ -55,6 +54,11 @@ final class NumberArrayData extends ContinuousArrayData {
this.array = array;
}
@Override
public Class<?> getElementType() {
return double.class;
}
@Override
public ArrayData copy() {
return new NumberArrayData(array.clone(), (int) length());
@ -298,4 +302,41 @@ final class NumberArrayData extends ContinuousArrayData {
return returnValue;
}
@Override
public long fastPush(final int arg) {
return fastPush((double)arg);
}
@Override
public long fastPush(final long arg) {
return fastPush((double)arg);
}
@Override
public long fastPush(final double arg) {
final int len = (int)length;
if (len == array.length) {
//note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
}
@Override
public double fastPopDouble() {
if (length == 0) {
throw new ClassCastException();
}
final int newLength = (int)--length;
final double elem = array[newLength];
array[newLength] = 0;
return elem;
}
@Override
public Object fastPopObject() {
return fastPopDouble();
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.arrays;
/**
* Marker interface for any ContinuousArray with numeric elements
* (int, long or double)
* Used for type checks that throw ClassCastExceptions and force relinks
* for fast NativeArray specializations of builtin methods
*/
public interface NumericElements {
//empty
}

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -56,9 +55,14 @@ final class ObjectArrayData extends ContinuousArrayData {
this.array = array;
}
@Override
public Class<?> getElementType() {
return Object.class;
}
@Override
public ArrayData copy() {
return new ObjectArrayData(array.clone(), (int) length());
return new ObjectArrayData(array.clone(), (int)length);
}
@Override
@ -231,6 +235,42 @@ final class ObjectArrayData extends ContinuousArrayData {
return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
}
@Override
public long fastPush(final int arg) {
return fastPush((Object)arg);
}
@Override
public long fastPush(final long arg) {
return fastPush((Object)arg);
}
@Override
public long fastPush(final double arg) {
return fastPush((Object)arg);
}
@Override
public long fastPush(final Object arg) {
final int len = (int)length;
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
}
@Override
public Object fastPopObject() {
if (length == 0) {
return ScriptRuntime.UNDEFINED;
}
final int newLength = (int)--length;
final Object elem = array[newLength];
array[newLength] = ScriptRuntime.EMPTY;
return elem;
}
@Override
public Object pop() {
if (length() == 0) {

View File

@ -329,7 +329,7 @@ class SparseArrayData extends ArrayData {
}
@Override
protected ArrayData convert(final Class<?> type) {
public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
return this;
}

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.nio.Buffer;
import jdk.internal.dynalink.CallSiteDescriptor;
@ -134,7 +133,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
}
@Override
protected ArrayData convert(final Class<?> type) {
public ArrayData convert(final Class<?> type) {
throw new UnsupportedOperationException();
}

View File

@ -26,14 +26,16 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.GlobalConstants;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
@ -86,27 +88,41 @@ public final class PrimitiveLookup {
final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
if(desc.getNameTokenCount() > 2) {
//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.
if (desc.getNameTokenCount() > 2) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final FindProperty find = wrappedReceiver.findProperty(name, true);
if(find == null) {
if (find == null) {
// Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
return null;
} else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
}
final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
}
if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
final GuardedInvocation link = proto.lookup(desc, request);
if (link != null) {
final MethodHandle invocation = link.getInvocation();
final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
}
}
}
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
if (link != null) {
MethodHandle method = link.getInvocation();
@ -116,8 +132,10 @@ public final class PrimitiveLookup {
assert receiverType.isAssignableFrom(wrapType.returnType());
method = MH.filterArguments(method, 0, MH.asType(wrapFilter, wrapType.changeReturnType(receiverType)));
}
return new GuardedInvocation(method, guard, link.getSwitchPoints(), null);
}
return null;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Simple benchmark to measure charCodeAt specialized method performance
*/
var str = "sghjkdsfkjghsdfjkfkjdfkjdfjkdfjkfdjkfdkfldjfhdfpkjdhafgksdjfgldfgjldfkjgdlfjgldkfjgkldfj";
var RESULT1 = 9187;
var RESULT2 = 1496;
function f() {
var len = str.length;
var c = 0;
for (var i = 0; i < len; i++) {
c += str.charCodeAt(i);
}
return c;
}
function bench(res) {
var d = new Date;
var sum = 0;
for (var i = 0; i < 1e6; i++) {
sum |= f();
}
if (sum == res) {
print("Verified OK");
} else {
print("Verification failed " + sum + " should be " + res);
}
print((new Date - d) + " ms");
}
bench(RESULT1);
print("Replacing charCodeAt... ");
String.prototype.charCodeAt = function() { return 17; }
bench(RESULT2);
print("Done");

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Simple benchmark to measure push/pop specialized method performance
*/
var a = [];
var RESULT = 15;
function bench() {
var sum = 0;
for (var i=0;i<10;i++) {
a.push(i);
}
for (var i=0;i<10;i++) {
sum |= a.pop();
}
return sum;
}
function runbench() {
var sum = 0;
for (var iters = 0; iters<1e8; iters++) {
sum |= bench();
}
return sum;
}
var d = new Date;
var res = runbench();
print((new Date - d) + " ms");
print();
if (res != RESULT) {
print("ERROR: Wrong result - should be " + RESULT);
} else {
print("Verified OK - result is correct");
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* apply_to_call5.js - do one apply to call specialization, then override, apply and make sure it reverts (i.e. stops
* calling call)
*
* @test
* @run
*/
print("start");
var x = {
a : 0,
b : 0,
c : 0,
initialize : function(x,y,z) {
this.a = x;
this.b = y;
this.c = z;
}
};
function test() {
x.initialize.apply(x, arguments);
}
test(4711,23,17);
print(x.a);
print(x.b);
print(x.c);
print("Overwriting apply now");
x.initialize.apply = function() { print("New function for apply - not a property"); }
test(4712);
print(x.a);
var x2 = {
a : 0,
b : 0,
c : 0,
initialize : function(x,y,z) {
this.a = x;
this.b = y;
this.c = z;
}
};
function test2() {
x2.initialize.apply(x2, arguments);
}
test2(4711,23,17);
print(x2.a);
print(x2.b);
print(x2.c);
print("Overwriting apply now");
x2.initialize['apply'] = function() { print("New function for apply - not a property"); }
test(4712);
print(x2.a);
var x3 = {
a : 0,
b : 0,
c : 0,
initialize : function(x,y,z) {
this.a = x;
this.b = y;
this.c = z;
}
};
function test3() {
x3.initialize.apply(x3, arguments);
}
test3(4711,23,17);
print(x3.a);
print(x3.b);
print(x3.c);
print("Overwriting apply now");
eval("x3.initialize['apply'] = function() { print('New function for apply - not a property'); }");
test(4712);
print(x3.a);

View File

@ -0,0 +1,19 @@
start
4711
23
17
Overwriting apply now
New function for apply - not a property
4711
4711
23
17
Overwriting apply now
New function for apply - not a property
4711
4711
23
17
Overwriting apply now
New function for apply - not a property
4711

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* fastpushpop.js: make sure guards work for fast push implementation
* and normal one
*
* @test
* @run
*/
var a = [1,2,3];
a.push(4);
a.push(5);
a.push(6);
print(a);
var a2 = Object.defineProperty(a,"length", { writable: false });
try {
a2.push(7);
} catch (e) {
print("first: " + (e instanceof TypeError));
}
print(a2);
var b = [1,2,3,,,,4711.17,"dingo!"];
b.push(4);
b.push(5);
b.push(6);
print(b);
var b2 = Object.defineProperty(b,"length", { writable: false });
try {
b2.push(7);
} catch (e) {
print("second: " + (e instanceof TypeError));
}
print(b2);

View File

@ -0,0 +1,6 @@
1,2,3,4,5,6
first: true
1,2,3,4,5,6,7
1,2,3,,,,4711.17,dingo!,4,5,6
second: true
1,2,3,,,,4711.17,dingo!,4,5,6,7

View File

@ -54,7 +54,7 @@ function load_bench(arg) {
}
}
print_verbose(arg, "loading '" + arg.name + "' [" + f + "]...");
print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
load(file_name);
}
@ -139,7 +139,7 @@ function run_one_benchmark(arg, iters) {
mean_score /= iters;
} catch (e) {
print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
if (e instanceof java.lang.Throwable) {
if (is_this_nashorn() && e instanceof java.lang.Throwable) {
e.printStackTrace();
}
mean_score = min_score = max_score = 0;
@ -148,7 +148,7 @@ function run_one_benchmark(arg, iters) {
var res = mean_score.toFixed(0);
if (verbose) {
res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
}
print_always(arg, res);
}