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
nashorn
buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen
samples
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal
test

@ -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) {

@ -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);

@ -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);
}
}

@ -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) {

@ -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);
}
};
}

@ -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;

@ -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();

@ -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;
}

@ -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;
}

@ -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);
}
/**

@ -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;
}

@ -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;
}

@ -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;
}

@ -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,

@ -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));
}
/**

@ -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;

@ -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);

@ -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)}
*

@ -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;

@ -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);
}
}

@ -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();
}
}
}

@ -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");

@ -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);

@ -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;

@ -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);

@ -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);

@ -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);

@ -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);

@ -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;

@ -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);
}

@ -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;
}
}
}

@ -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);

@ -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);

@ -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);

@ -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;

@ -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);
}

@ -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;
}

@ -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 ";
}
});
}

@ -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

@ -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
*/

@ -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) {

@ -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);
}
}

@ -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) {

@ -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
*/

@ -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");
}

@ -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);

@ -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();
}

@ -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();
}
/**

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

@ -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;
}

@ -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");

@ -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()

@ -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);

@ -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");
}
}

@ -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 });
}
}
}

@ -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) {

@ -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;
}
}

@ -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;
}

@ -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;

@ -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
*

@ -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;

@ -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
}
}

@ -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();
}
}

@ -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
}

@ -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
}

@ -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();
}
}

@ -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();
}
}

@ -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
}

@ -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) {

@ -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;
}

@ -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();
}

@ -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;
}
}

@ -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");

@ -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");
}

@ -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);

@ -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

@ -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);

@ -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

@ -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);
}