# HG changeset patch # User lana # Date 1374540026 25200 # Node ID 12baff1ad7a08b5fc56934689dea622aeff306a1 # Parent d0545441225ecc50e34de62d1f7dfa49e7184fad# Parent 42107475be8da6dc816331490864495d1d61d896 Merge diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/build.xml --- a/nashorn/buildtools/nasgen/build.xml Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/build.xml Mon Jul 22 17:40:26 2013 -0700 @@ -42,7 +42,8 @@ destdir="${build.classes.dir}" classpath="${javac.classpath}" debug="${javac.debug}" - includeantruntime="false"> + includeantruntime="false" fork="true"> + diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Mon Jul 22 17:40:26 2013 -0700 @@ -25,6 +25,7 @@ package jdk.nashorn.internal.tools.nasgen; +import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL; import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE; import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC; import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; @@ -36,14 +37,24 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME; import static jdk.nashorn.internal.tools.nasgen.StringConstants.GET_CLASS_NAME_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_NEWPROPERTY_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.LOOKUP_TYPE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_NEWMAP_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_CREATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ACCESSORPROPERTY_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.LIST_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.ARRAYLIST_INIT_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTION_ADD_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.COLLECTIONS_EMPTY_LIST; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_SETISSHARED; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_SETISSHARED_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC; @@ -160,18 +171,30 @@ return new MethodGenerator(mv, access, name, desc); } - static void emitStaticInitPrefix(final MethodGenerator mi, final String className) { + static void emitStaticInitPrefix(final MethodGenerator mi, final String className, final int memberCount) { mi.visitCode(); - mi.pushNull(); - mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); - mi.loadClass(className); - mi.invokeStatic(MAP_TYPE, MAP_NEWMAP, MAP_NEWMAP_DESC); - // stack: PropertyMap + if (memberCount > 0) { + // new ArrayList(int) + mi.newObject(ARRAYLIST_TYPE); + mi.dup(); + mi.push(memberCount); + mi.invokeSpecial(ARRAYLIST_TYPE, INIT, ARRAYLIST_INIT_DESC); + // stack: ArrayList + } else { + // java.util.Collections.EMPTY_LIST + mi.getStatic(COLLECTIONS_TYPE, COLLECTIONS_EMPTY_LIST, LIST_DESC); + // stack List + } } static void emitStaticInitSuffix(final MethodGenerator mi, final String className) { - // stack: PropertyMap - mi.putStatic(className, MAP_FIELD_NAME, MAP_DESC); + // stack: Collection + // pmap = PropertyMap.newMap(Collection); + mi.invokeStatic(PROPERTYMAP_TYPE, PROPERTYMAP_NEWMAP, PROPERTYMAP_NEWMAP_DESC); + // pmap.setIsShared(); + mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_SETISSHARED, PROPERTYMAP_SETISSHARED_DESC); + // $nasgenmap$ = pmap; + mi.putStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC); mi.returnVoid(); mi.computeMaxs(); mi.visitEnd(); @@ -235,9 +258,9 @@ } static void addMapField(final ClassVisitor cv) { - // add a MAP static field - final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC, - MAP_FIELD_NAME, MAP_DESC, null, null); + // add a PropertyMap static field + final FieldVisitor fv = cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, + PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC, null, null); if (fv != null) { fv.visitEnd(); } @@ -278,7 +301,11 @@ static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) { final String propertyName = memInfo.getName(); - // stack: PropertyMap + // stack: Collection + // dup of Collection instance + mi.dup(); + + // property = AccessorProperty.create(key, flags, getter, setter); mi.loadLiteral(propertyName); // setup flags mi.push(memInfo.getAttributes()); @@ -292,13 +319,21 @@ javaName = SETTER_PREFIX + memInfo.getJavaName(); mi.visitLdcInsn(new Handle(H_INVOKEVIRTUAL, className, javaName, setterDesc(memInfo))); } - mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); - // stack: PropertyMap + mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC); + // boolean Collection.add(property) + mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC); + // pop return value of Collection.add + mi.pop(); + // stack: Collection } static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo getter, final MemberInfo setter) { final String propertyName = getter.getName(); - // stack: PropertyMap + // stack: Collection + // dup of Collection instance + mi.dup(); + + // property = AccessorProperty.create(key, flags, getter, setter); mi.loadLiteral(propertyName); // setup flags mi.push(getter.getAttributes()); @@ -312,8 +347,12 @@ mi.visitLdcInsn(new Handle(H_INVOKESTATIC, className, setter.getJavaName(), setter.getJavaDesc())); } - mi.invokeStatic(LOOKUP_TYPE, LOOKUP_NEWPROPERTY, LOOKUP_NEWPROPERTY_DESC); - // stack: PropertyMap + mi.invokeStatic(ACCESSORPROPERTY_TYPE, ACCESSORPROPERTY_CREATE, ACCESSORPROPERTY_CREATE_DESC); + // boolean Collection.add(property) + mi.invokeInterface(COLLECTION_TYPE, COLLECTION_ADD, COLLECTION_ADD_DESC); + // pop return value of Collection.add + mi.pop(); + // stack: Collection } static ScriptClassInfo getScriptClassInfo(final String fileName) throws IOException { diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java Mon Jul 22 17:40:26 2013 -0700 @@ -32,11 +32,11 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.CONSTRUCTOR_SUFFIX; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC; @@ -129,7 +129,7 @@ private void emitStaticInitializer() { final MethodGenerator mi = makeStaticInitializer(); - emitStaticInitPrefix(mi, className); + emitStaticInitPrefix(mi, className, memberCount); for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { if (memInfo.isConstructorFunction() || memInfo.isConstructorProperty()) { @@ -170,10 +170,10 @@ private void loadMap(final MethodGenerator mi) { if (memberCount > 0) { - mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC); // make sure we use duplicated PropertyMap so that original map - // stays intact and so can be used for many globals in same context - mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + // stays intact and so can be used for many globals. + mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_DUPLICATE, PROPERTYMAP_DUPLICATE_DESC); } } diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Mon Jul 22 17:40:26 2013 -0700 @@ -57,6 +57,7 @@ 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.ILOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; @@ -347,6 +348,10 @@ } // invokes, field get/sets + void invokeInterface(final String owner, final String method, final String desc) { + super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc); + } + void invokeVirtual(final String owner, final String method, final String desc) { super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc); } diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java Mon Jul 22 17:40:26 2013 -0700 @@ -30,11 +30,11 @@ import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DUPLICATE_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_TYPE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_DUPLICATE_DESC; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_FIELD_NAME; +import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE; import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPE_SUFFIX; @@ -67,6 +67,7 @@ // add emitStaticInitializer(); } + // add emitConstructor(); @@ -106,7 +107,7 @@ private void emitStaticInitializer() { final MethodGenerator mi = makeStaticInitializer(); - emitStaticInitPrefix(mi, className); + emitStaticInitPrefix(mi, className, memberCount); for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { if (memInfo.isPrototypeFunction() || memInfo.isPrototypeProperty()) { linkerAddGetterSetter(mi, className, memInfo); @@ -124,10 +125,10 @@ mi.loadThis(); if (memberCount > 0) { // call "super(map$)" - mi.getStatic(className, MAP_FIELD_NAME, MAP_DESC); + mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC); // make sure we use duplicated PropertyMap so that original map - // stays intact and so can be used for many globals in same context - mi.invokeVirtual(MAP_TYPE, MAP_DUPLICATE, MAP_DUPLICATE_DESC); + // stays intact and so can be used for many global. + mi.invokeVirtual(PROPERTYMAP_TYPE, PROPERTYMAP_DUPLICATE, PROPERTYMAP_DUPLICATE_DESC); mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC); // initialize Function type fields initFunctionFields(mi); diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java Mon Jul 22 17:40:26 2013 -0700 @@ -37,10 +37,7 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.CLINIT; import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.MAP_FIELD_NAME; import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC; -import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_INIT_DESC; import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE; import java.io.BufferedInputStream; @@ -159,14 +156,7 @@ public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc) { if (isConstructor && opcode == INVOKESPECIAL && INIT.equals(name) && SCRIPTOBJECT_TYPE.equals(owner)) { - - // replace call to empty super-constructor with one passing PropertyMap argument - if (DEFAULT_INIT_DESC.equals(desc)) { - super.visitFieldInsn(GETSTATIC, scriptClassInfo.getJavaName(), MAP_FIELD_NAME, MAP_DESC); - super.visitMethodInsn(INVOKESPECIAL, SCRIPTOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC); - } else { - super.visitMethodInsn(opcode, owner, name, desc); - } + super.visitMethodInsn(opcode, owner, name, desc); if (memberCount > 0) { // initialize @Property fields if needed @@ -256,7 +246,7 @@ } // Now generate $clinit$ final MethodGenerator mi = ClassGenerator.makeStaticInitializer(this, $CLINIT$); - ClassGenerator.emitStaticInitPrefix(mi, className); + ClassGenerator.emitStaticInitPrefix(mi, className, memberCount); if (memberCount > 0) { for (final MemberInfo memInfo : scriptClassInfo.getMembers()) { if (memInfo.isInstanceProperty() || memInfo.isInstanceFunction()) { diff -r d0545441225e -r 12baff1ad7a0 nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java --- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Mon Jul 22 17:40:26 2013 -0700 @@ -27,10 +27,14 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Method; +import java.util.Collection; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import jdk.internal.org.objectweb.asm.Type; -import jdk.nashorn.internal.lookup.Lookup; import jdk.nashorn.internal.objects.PrototypeObject; import jdk.nashorn.internal.objects.ScriptFunctionImpl; +import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; @@ -40,15 +44,41 @@ */ @SuppressWarnings("javadoc") public interface StringConstants { + // standard jdk types, methods static final Type TYPE_METHOD = Type.getType(Method.class); 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_CLASS = Type.getType(Class.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); - // Nashorn types - static final Type TYPE_LOOKUP = Type.getType(Lookup.class); + static final String CLINIT = ""; + static final String INIT = ""; + static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE); + + static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); + static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); + static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); + static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); + static final String ARRAYLIST_TYPE = TYPE_ARRAYLIST.getInternalName(); + static final String COLLECTION_TYPE = TYPE_COLLECTION.getInternalName(); + static final String COLLECTIONS_TYPE = TYPE_COLLECTIONS.getInternalName(); + + // java.util.Collection.add(Object) + static final String COLLECTION_ADD = "add"; + static final String COLLECTION_ADD_DESC = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, TYPE_OBJECT); + // java.util.ArrayList.(int) + static final String ARRAYLIST_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE); + // java.util.Collections.EMPTY_LIST + static final String COLLECTIONS_EMPTY_LIST = "EMPTY_LIST"; + static final String LIST_DESC = TYPE_LIST.getDescriptor(); + + // Nashorn types, methods + static final Type TYPE_ACCESSORPROPERTY = Type.getType(AccessorProperty.class); static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class); static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class); static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class); @@ -57,54 +87,56 @@ static final String PROTOTYPE_SUFFIX = "$Prototype"; static final String CONSTRUCTOR_SUFFIX = "$Constructor"; + // This field name is known to Nashorn runtime (Context). // Synchronize the name change, if needed at all. - static final String MAP_FIELD_NAME = "$nasgenmap$"; + static final String PROPERTYMAP_FIELD_NAME = "$nasgenmap$"; static final String $CLINIT$ = "$clinit$"; - static final String CLINIT = ""; - static final String INIT = ""; - static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE); - static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); + // AccessorProperty + static final String ACCESSORPROPERTY_TYPE = TYPE_ACCESSORPROPERTY.getInternalName(); + static final String ACCESSORPROPERTY_CREATE = "create"; + static final String ACCESSORPROPERTY_CREATE_DESC = + Type.getMethodDescriptor(TYPE_ACCESSORPROPERTY, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE); - static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName(); + // PropertyMap + static final String PROPERTYMAP_TYPE = TYPE_PROPERTYMAP.getInternalName(); + static final String PROPERTYMAP_DESC = TYPE_PROPERTYMAP.getDescriptor(); + static final String PROPERTYMAP_NEWMAP = "newMap"; + static final String PROPERTYMAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_COLLECTION); + static final String PROPERTYMAP_DUPLICATE = "duplicate"; + static final String PROPERTYMAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP); + static final String PROPERTYMAP_SETISSHARED = "setIsShared"; + static final String PROPERTYMAP_SETISSHARED_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP); - static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName(); - static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor(); - static final String OBJECT_ARRAY_DESC = Type.getDescriptor(Object[].class); + // PrototypeObject + static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName(); + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor"; + static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT); + // ScriptFunction static final String SCRIPTFUNCTION_TYPE = TYPE_SCRIPTFUNCTION.getInternalName(); + static final String SCRIPTFUNCTION_SETARITY = "setArity"; + static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE); + static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype"; + static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT); + + // ScriptFunctionImpl static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName(); static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction"; 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); - static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY); static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY); - static final String SCRIPTFUNCTION_SETARITY = "setArity"; - static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE); - static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype"; - static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT); - static final String PROTOTYPEOBJECT_TYPE = TYPE_PROTOTYPEOBJECT.getInternalName(); - static final String PROTOTYPEOBJECT_SETCONSTRUCTOR = "setConstructor"; - static final String PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT, TYPE_OBJECT); + + // ScriptObject static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName(); - static final String MAP_TYPE = TYPE_PROPERTYMAP.getInternalName(); - static final String MAP_DESC = TYPE_PROPERTYMAP.getDescriptor(); - static final String MAP_NEWMAP = "newMap"; - static final String MAP_NEWMAP_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_CLASS); - static final String MAP_DUPLICATE = "duplicate"; - static final String MAP_DUPLICATE_DESC = Type.getMethodDescriptor(TYPE_PROPERTYMAP); - static final String MAP_SETFLAGS = "setFlags"; - static final String LOOKUP_TYPE = TYPE_LOOKUP.getInternalName(); - static final String LOOKUP_GETMETHOD = "getMethod"; - static final String LOOKUP_NEWPROPERTY = "newProperty"; - static final String LOOKUP_NEWPROPERTY_DESC = - Type.getMethodDescriptor(TYPE_PROPERTYMAP, TYPE_PROPERTYMAP, TYPE_STRING, Type.INT_TYPE, TYPE_METHODHANDLE, TYPE_METHODHANDLE); + static final String SCRIPTOBJECT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_PROPERTYMAP); + static final String GETTER_PREFIX = "G$"; static final String SETTER_PREFIX = "S$"; diff -r d0545441225e -r 12baff1ad7a0 nashorn/docs/JavaScriptingProgrammersGuide.html --- a/nashorn/docs/JavaScriptingProgrammersGuide.html Thu Jul 18 03:39:39 2013 -0700 +++ b/nashorn/docs/JavaScriptingProgrammersGuide.html Mon Jul 22 17:40:26 2013 -0700 @@ -501,14 +501,19 @@ var anArrayListWithSize = new ArrayList(16) -In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name: +In the special case of inner classes, you can either use the JVM fully qualified name, meaning using the dollar sign in the class name, or you can use the dot:

  var ftype = Java.type("java.awt.geom.Arc2D$Float")
 
+and + +

+ var ftype = Java.type("java.awt.geom.Arc2D.Float")
+
-However, once you retrieved the outer class, you can access the inner class as a property on it: +both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An alternative way to access the inner class is as a property of the outer class:

  var arctype = Java.type("java.awt.geom.Arc2D")
diff -r d0545441225e -r 12baff1ad7a0 nashorn/make/build-nasgen.xml
--- a/nashorn/make/build-nasgen.xml	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/make/build-nasgen.xml	Mon Jul 22 17:40:26 2013 -0700
@@ -42,11 +42,6 @@
             
             
         
-
-        
-            
-            
-        
     
 
     
@@ -66,7 +61,6 @@
             
                 
             
-            
         
 
         
@@ -75,7 +69,6 @@
             
                 
             
-            
         
     
 
diff -r d0545441225e -r 12baff1ad7a0 nashorn/make/build.xml
--- a/nashorn/make/build.xml	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/make/build.xml	Mon Jul 22 17:40:26 2013 -0700
@@ -100,7 +100,8 @@
            target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
-           includeantruntime="false">
+           includeantruntime="false" fork="true">
+      
       
       
       
@@ -218,8 +219,10 @@
            target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
-           includeantruntime="false">
-        
+           includeantruntime="false" fork="true">
+        
+        
+        
     
 
     
@@ -235,44 +238,31 @@
   
 
   
-    
+    
 
-    
-    
-    
-    
-    
-    
-    
+grant codeBase "file:/${basedir}/${nashorn.internal.tests.jar}" {
+    permission java.security.AllPermission;
+};
 
-    
-    
-    
-    
-    
-    
-    
+grant codeBase "file:/${basedir}/${file.reference.testng.jar}" {
+    permission java.security.AllPermission;
+};
 
-    
-    
-    
-    
-    
-    
-    
+grant codeBase "file:/${basedir}/test/script/trusted/*" {
+    permission java.security.AllPermission;
+};
 
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
+grant codeBase "file:/${basedir}/test/script/basic/*" {
+    permission java.io.FilePermission "${basedir}/test/script/-", "read";
+    permission java.io.FilePermission "$${user.dir}", "read";
+    permission java.util.PropertyPermission "user.dir", "read";
+    permission java.util.PropertyPermission "nashorn.test.*", "read";
+};
+
+grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
+    permission java.util.PropertyPermission "java.security.policy", "read";
+};
+    
 
     \/    
     ///   
diff -r d0545441225e -r 12baff1ad7a0 nashorn/make/code_coverage.xml
--- a/nashorn/make/code_coverage.xml	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/make/code_coverage.xml	Mon Jul 22 17:40:26 2013 -0700
@@ -60,16 +60,8 @@
     
       
         
-        
       
     
-
-    
-      
-        
-      
-      
-    
   
 
   
diff -r d0545441225e -r 12baff1ad7a0 nashorn/make/project.properties
--- a/nashorn/make/project.properties	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/make/project.properties	Mon Jul 22 17:40:26 2013 -0700
@@ -200,6 +200,9 @@
 
 # test262 test frameworks
 test262-test-sys-prop.test.js.framework=\
+    --class-cache-size=0 \
+    --no-java \
+    --no-typed-arrays \
     -timezone=PST \
     ${test.script.dir}/test262.js \
     ${test262.dir}/test/harness/framework.js \
diff -r d0545441225e -r 12baff1ad7a0 nashorn/makefiles/BuildNashorn.gmk
--- a/nashorn/makefiles/BuildNashorn.gmk	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/makefiles/BuildNashorn.gmk	Mon Jul 22 17:40:26 2013 -0700
@@ -71,7 +71,6 @@
 $(BUILD_NASGEN): $(BUILD_NASHORN)
 
 # Copy classes to final classes dir and run nasgen to modify classes in jdk.nashorn.internal.objects package
-# Finally rename classes in jdk.nashorn.internal.objects package
 $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run: $(BUILD_NASGEN)
 	$(ECHO) Running nasgen
 	$(MKDIR) -p $(@D)
@@ -80,9 +79,6 @@
 	$(FIXPATH) $(JAVA) \
 		-cp "$(NASHORN_OUTPUTDIR)/nasgen_classes$(PATH_SEP)$(NASHORN_OUTPUTDIR)/nashorn_classes" \
 		jdk.nashorn.internal.tools.nasgen.Main $(@D) jdk.nashorn.internal.objects $(@D)
-	for f in `$(FIND) $(@D)/jdk/nashorn/internal/objects/ -name "*.class"`; do \
-	  mv "$$f" `$(ECHO) "$$f" | $(SED) "s/\.class$$/\.clazz/"`; \
-        done
 	$(TOUCH) $@
 
 # Version file needs to be processed with version numbers
@@ -104,7 +100,7 @@
     $(NASHORN_OUTPUTDIR)/classes/_the.nasgen.run \
     $(VERSION_FILE),\
     SRCS:=$(NASHORN_OUTPUTDIR)/classes,\
-    SUFFIXES:=.class .clazz .js .properties Factory,\
+    SUFFIXES:=.class .js .properties Factory,\
     MANIFEST:=$(NASHORN_TOPDIR)/src/META-INF/MANIFEST.MF,\
     EXTRA_MANIFEST_ATTR:=$(MANIFEST_ATTRIBUTES),\
     SKIP_METAINF:=true,\
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/DynamicLinker.java
--- a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java	Mon Jul 22 17:40:26 2013 -0700
@@ -144,6 +144,9 @@
     private static final String CLASS_NAME = DynamicLinker.class.getName();
     private static final String RELINK_METHOD_NAME = "relink";
 
+    private static final String INITIAL_LINK_CLASS_NAME = "java.lang.invoke.MethodHandleNatives";
+    private static final String INITIAL_LINK_METHOD_NAME = "linkCallSite";
+
     private final LinkerServices linkerServices;
     private final int runtimeContextArgCount;
     private final boolean syncOnRelink;
@@ -262,20 +265,54 @@
     }
 
     /**
-     * Returns a stack trace element describing the location of the call site currently being relinked on the current
+     * Returns a stack trace element describing the location of the call site currently being linked on the current
      * thread. The operation internally creates a Throwable object and inspects its stack trace, so it's potentially
      * expensive. The recommended usage for it is in writing diagnostics code.
-     * @return a stack trace element describing the location of the call site currently being relinked, or null if it is
-     * not invoked while a call site is being relinked.
+     * @return a stack trace element describing the location of the call site currently being linked, or null if it is
+     * not invoked while a call site is being linked.
      */
-    public static StackTraceElement getRelinkedCallSiteLocation() {
+    public static StackTraceElement getLinkedCallSiteLocation() {
         final StackTraceElement[] trace = new Throwable().getStackTrace();
         for(int i = 0; i < trace.length - 1; ++i) {
             final StackTraceElement frame = trace[i];
-            if(RELINK_METHOD_NAME.equals(frame.getMethodName()) && CLASS_NAME.equals(frame.getClassName())) {
+            if(isRelinkFrame(frame) || isInitialLinkFrame(frame)) {
                 return trace[i + 1];
             }
         }
         return null;
     }
+
+    /**
+     * Deprecated because of not precise name.
+     * @deprecated Use {@link #getLinkedCallSiteLocation()} instead.
+     * @return see non-deprecated method
+     */
+    @Deprecated
+    public static StackTraceElement getRelinkedCallSiteLocation() {
+        return getLinkedCallSiteLocation();
+    }
+
+    /**
+     * Returns true if the frame represents {@code MethodHandleNatives.linkCallSite()}, the frame immediately on top of
+     * the call site frame when the call site is being linked for the first time.
+     * @param frame the frame
+     * @return true if this frame represents {@code MethodHandleNatives.linkCallSite()}
+     */
+    private static boolean isInitialLinkFrame(final StackTraceElement frame) {
+        return testFrame(frame, INITIAL_LINK_METHOD_NAME, INITIAL_LINK_CLASS_NAME);
+    }
+
+    /**
+     * Returns true if the frame represents {@code DynamicLinker.relink()}, the frame immediately on top of the call
+     * site frame when the call site is being relinked (linked for second and subsequent times).
+     * @param frame the frame
+     * @return true if this frame represents {@code DynamicLinker.relink()}
+     */
+    private static boolean isRelinkFrame(final StackTraceElement frame) {
+        return testFrame(frame, RELINK_METHOD_NAME, CLASS_NAME);
+    }
+
+    private static boolean testFrame(final StackTraceElement frame, final String methodName, final String className) {
+        return methodName.equals(frame.getMethodName()) && className.equals(frame.getClassName());
+    }
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java
--- a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Mon Jul 22 17:40:26 2013 -0700
@@ -86,9 +86,14 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -109,10 +114,11 @@
  * @author Attila Szegedi
  */
 abstract class AbstractJavaLinker implements GuardingDynamicLinker {
+
     final Class clazz;
     private final MethodHandle classGuard;
     private final MethodHandle assignableGuard;
-    private final Map propertyGetters = new HashMap<>();
+    private final Map propertyGetters = new HashMap<>();
     private final Map propertySetters = new HashMap<>();
     private final Map methods = new HashMap<>();
 
@@ -129,22 +135,19 @@
         // Add methods and properties
         for(Method method: introspector.getMethods()) {
             final String name = method.getName();
-            final MethodHandle methodHandle = introspector.unreflect(method);
             // Add method
-            addMember(name, methodHandle, methods);
+            addMember(name, method, methods);
             // Add the method as a property getter and/or setter
             if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
                 // Property getter
-                setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect(
-                        getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
+                setPropertyGetter(method, 3);
             } else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
                     method.getReturnType() == boolean.class) {
                 // Boolean property getter
-                setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect(
-                        getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
+                setPropertyGetter(method, 2);
             } else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
                 // Property setter
-                addMember(decapitalize(name.substring(3)), methodHandle, propertySetters);
+                addMember(decapitalize(name.substring(3)), method, propertySetters);
             }
         }
 
@@ -156,7 +159,8 @@
                 setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
             }
             if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
-                addMember(name, introspector.unreflectSetter(field), propertySetters);
+                addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
+                        propertySetters);
             }
         }
 
@@ -192,38 +196,135 @@
 
     abstract FacetIntrospector createFacetIntrospector();
 
-    void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
-        propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType));
+    Collection getReadablePropertyNames() {
+        return getUnmodifiableKeys(propertyGetters);
+    }
+
+    Collection getWritablePropertyNames() {
+        return getUnmodifiableKeys(propertySetters);
+    }
+
+    Collection getMethodNames() {
+        return getUnmodifiableKeys(methods);
+    }
+
+    private static Collection getUnmodifiableKeys(Map m) {
+        return Collections.unmodifiableCollection(m.keySet());
+    }
+
+    /**
+     * Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
+     * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
+     * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
+     * instead.
+     * @param name name of the property
+     * @param handle the method handle that implements the property getter
+     * @param validationType the validation type for the property
+     */
+    private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) {
+        propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
     }
 
-    private void addMember(String name, MethodHandle mh, Map methodMap) {
+    /**
+     * Sets the specified reflective method to be the property getter for the specified property.
+     * @param getter the getter method
+     * @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
+     * names starting with "is".
+     */
+    private void setPropertyGetter(Method getter, int prefixLen) {
+        setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
+                getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
+    }
+
+    /**
+     * Sets the specified method handle to be the property getter for the specified property. Note that you can only
+     * use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
+     * that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
+     * instead.
+     * @param name name of the property
+     * @param handle the method handle that implements the property getter
+     * @param validationType the validation type for the property
+     */
+    void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
+        setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
+    }
+
+    private void addMember(String name, AccessibleObject ao, Map methodMap) {
+        addMember(name, createDynamicMethod(ao), methodMap);
+    }
+
+    private void addMember(String name, SingleDynamicMethod method, Map methodMap) {
         final DynamicMethod existingMethod = methodMap.get(name);
-        final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name);
+        final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
         if(newMethod != existingMethod) {
             methodMap.put(name, newMethod);
         }
     }
 
-    static DynamicMethod createDynamicMethod(Iterable methodHandles, Class clazz, String name) {
+    /**
+     * Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
+     * methods should represent all overloads of the same name (or all constructors of the class).
+     * @param members the reflective members
+     * @param clazz the class declaring the reflective members
+     * @param name the common name of the reflective members.
+     * @return a dynamic method representing all the specified reflective members.
+     */
+    static DynamicMethod createDynamicMethod(Iterable members, Class clazz, String name) {
         DynamicMethod dynMethod = null;
-        for(MethodHandle methodHandle: methodHandles) {
-            dynMethod = addMember(methodHandle, dynMethod, clazz, name);
+        for(AccessibleObject method: members) {
+            dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
         }
         return dynMethod;
     }
 
-    private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class clazz, String name) {
+    /**
+     * Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
+     * distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
+     * dynamic method when needed.
+     * @param m the reflective member
+     * @return the single dynamic method representing the reflective member
+     */
+    private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) {
+        if(CallerSensitiveDetector.isCallerSensitive(m)) {
+            return new CallerSensitiveDynamicMethod(m);
+        }
+        final Member member = (Member)m;
+        return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
+    }
+
+    /**
+     * Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
+     * only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
+     * unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
+     * unreflector as its caller, and thus completely useless.
+     * @param m the method or constructor
+     * @return the method handle
+     */
+    private static MethodHandle unreflectSafely(AccessibleObject m) {
+        if(m instanceof Method) {
+            final Method reflMethod = (Method)m;
+            final MethodHandle handle = SafeUnreflector.unreflect(reflMethod);
+            if(Modifier.isStatic(reflMethod.getModifiers())) {
+                return StaticClassIntrospector.editStaticMethodHandle(handle);
+            }
+            return handle;
+        }
+        return StaticClassIntrospector.editConstructorMethodHandle(SafeUnreflector.unreflectConstructor(
+                (Constructor)m));
+    }
+
+    private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class clazz, String name) {
         if(existing == null) {
-            return new SimpleDynamicMethod(mh, clazz, name);
-        } else if(existing.contains(mh)) {
+            return method;
+        } else if(existing.contains(method)) {
             return existing;
-        } else if(existing instanceof SimpleDynamicMethod) {
+        } else if(existing instanceof SingleDynamicMethod) {
             final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
-            odm.addMethod(((SimpleDynamicMethod)existing));
-            odm.addMethod(mh);
+            odm.addMethod(((SingleDynamicMethod)existing));
+            odm.addMethod(method);
             return odm;
         } else if(existing instanceof OverloadedDynamicMethod) {
-            ((OverloadedDynamicMethod)existing).addMethod(mh);
+            ((OverloadedDynamicMethod)existing).addMethod(method);
             return existing;
         }
         throw new AssertionError();
@@ -296,7 +397,7 @@
     private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
         switch(callSiteDescriptor.getNameTokenCount()) {
             case 3: {
-                return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices,
+                return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
                         callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
             }
             default: {
@@ -305,16 +406,16 @@
         }
     }
 
-    private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType,
+    private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
             LinkerServices linkerServices, String methodName, Map methodMap){
-        final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap);
-        return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType));
+        final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
+        return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
     }
 
-    private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices,
-            String methodName, Map methodMap) {
+    private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
+            LinkerServices linkerServices, String methodName, Map methodMap) {
         final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
-        return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null;
+        return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
     }
 
     private static DynamicMethod getDynamicMethod(String methodName, Map methodMap) {
@@ -322,13 +423,13 @@
         return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
     }
 
-    private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
+    private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
             Map methodsMap) {
         // What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
         // to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
         // resolution works correctly in almost every situation. However, in presence of many language-specific
         // conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
-        // at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload
+        // at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
         // for performance reasons.
 
         // Is the method name lexically of the form "name(types)"?
@@ -377,8 +478,8 @@
                 final MethodType setterType = type.dropParameterTypes(1, 2);
                 // Bind property setter handle to the expected setter type and linker services. Type is
                 // MethodHandle(Object, String, Object)
-                final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType,
-                        linkerServices);
+                final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
+                        CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
 
                 // Cast getter to MethodHandle(O, N, V)
                 final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
@@ -415,9 +516,8 @@
             case 3: {
                 // Must have two arguments: target object and property value
                 assertParameterCount(callSiteDescriptor, 2);
-                final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(),
-                        linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND),
-                        propertySetters);
+                final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
+                        callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
                 // If we have a property setter with this name, this composite operation will always stop here
                 if(gi != null) {
                     return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
@@ -435,14 +535,13 @@
 
     private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
 
-    private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
-            boolean.class, AnnotatedMethodHandle.class));
-    private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments(
-            MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class);
-    private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class,
-            "handle", MethodHandle.class);
-    private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments(
-            MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE);
+    private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
+            boolean.class, AnnotatedDynamicMethod.class));
+    private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
+            MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
+    private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
+            "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class));
+    private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
 
     private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
             LinkerServices linkerServices, List ops) throws Exception {
@@ -455,16 +554,20 @@
                 // What's below is basically:
                 //   foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
                 // only with a bunch of method signature adjustments. Basically, retrieve method getter
-                // AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null,
+                // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
                 // or delegate to next component's invocation.
 
                 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
-                        AnnotatedMethodHandle.class));
-                // Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0)
-                final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER,
-                        MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0)));
+                        AnnotatedDynamicMethod.class));
+                final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
+                        GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
+                final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
+                        callSiteBoundMethodGetter);
+                // Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
+                final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
+                        MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
                 // Since it's in the target of a fold, drop the unnecessary second argument
-                // R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1)
+                // R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
                 final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
                         type.parameterType(1));
                 final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
@@ -472,19 +575,19 @@
 
                 final MethodHandle fallbackFolded;
                 if(nextComponent == null) {
-                    // Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null
-                    fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1,
-                            type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class));
+                    // Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
+                    fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
+                            type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
                 } else {
-                    // R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the
+                    // R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
                     // extra argument resulting from fold
                     fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
-                            0, AnnotatedMethodHandle.class);
+                            0, AnnotatedDynamicMethod.class);
                 }
 
-                // fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1))
+                // fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
                 final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
-                            IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
+                            IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
                 if(nextComponent == null) {
                     return getClassGuardedInvocationComponent(compositeGetter, type);
                 }
@@ -494,13 +597,13 @@
                 // Must have exactly one argument: receiver
                 assertParameterCount(callSiteDescriptor, 1);
                 // Fixed name
-                final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
+                final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
                         CallSiteDescriptor.NAME_OPERAND));
                 if(annGetter == null) {
                     // We have no such property, always delegate to the next component operation
                     return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
                 }
-                final MethodHandle getter = annGetter.handle;
+                final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
                 // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
                 // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
                 // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
@@ -508,6 +611,7 @@
                 // NOTE: No delegation to the next component operation if we have a property with this name, even if its
                 // value is null.
                 final ValidationType validationType = annGetter.validationType;
+                // TODO: we aren't using the type that declares the most generic getter here!
                 return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
                         type), clazz, validationType);
             }
@@ -623,14 +727,15 @@
     // args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
     // a typical property setter with variable name signature (target, name, value).
     private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
-            privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class,
+            privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
                     LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
     // Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
     private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
 
     @SuppressWarnings("unused")
-    private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) {
-        return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters);
+    private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices,
+            Object id) {
+        return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
     }
 
     private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
@@ -689,13 +794,24 @@
         return null;
     }
 
-    private static final class AnnotatedMethodHandle {
-        final MethodHandle handle;
+    private static final class AnnotatedDynamicMethod {
+        private final SingleDynamicMethod method;
         /*private*/ final ValidationType validationType;
 
-        AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) {
-            this.handle = handle;
+        AnnotatedDynamicMethod(SingleDynamicMethod method, ValidationType validationType) {
+            this.method = method;
             this.validationType = validationType;
         }
+
+        MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
+            return method.getInvocation(callSiteDescriptor, linkerServices);
+        }
+
+        @SuppressWarnings("unused")
+        MethodHandle getTarget(MethodHandles.Lookup lookup) {
+            MethodHandle inv = method.getTarget(lookup);
+            assert inv != null;
+            return inv;
+        }
     }
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java
--- a/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java	Mon Jul 22 17:40:26 2013 -0700
@@ -83,7 +83,6 @@
 
 package jdk.internal.dynalink.beans;
 
-import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodType;
 import java.util.LinkedList;
 import java.util.List;
@@ -95,7 +94,7 @@
  * @author Attila Szegedi
  */
 class ApplicableOverloadedMethods {
-    private final List methods;
+    private final List methods;
     private final boolean varArgs;
 
     /**
@@ -106,10 +105,10 @@
      * @param test applicability test. One of {@link #APPLICABLE_BY_SUBTYPING},
      * {@link #APPLICABLE_BY_METHOD_INVOCATION_CONVERSION}, or {@link #APPLICABLE_BY_VARIABLE_ARITY}.
      */
-    ApplicableOverloadedMethods(final List methods, final MethodType callSiteType,
+    ApplicableOverloadedMethods(final List methods, final MethodType callSiteType,
             final ApplicabilityTest test) {
         this.methods = new LinkedList<>();
-        for(MethodHandle m: methods) {
+        for(SingleDynamicMethod m: methods) {
             if(test.isApplicable(callSiteType, m)) {
                 this.methods.add(m);
             }
@@ -122,7 +121,7 @@
      *
      * @return list of all methods.
      */
-    List getMethods() {
+    List getMethods() {
         return methods;
     }
 
@@ -131,12 +130,12 @@
      *
      * @return a list of maximally specific methods.
      */
-    List findMaximallySpecificMethods() {
+    List findMaximallySpecificMethods() {
         return MaximallySpecific.getMaximallySpecificMethods(methods, varArgs);
     }
 
     abstract static class ApplicabilityTest {
-        abstract boolean isApplicable(MethodType callSiteType, MethodHandle method);
+        abstract boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method);
     }
 
     /**
@@ -144,8 +143,8 @@
      */
     static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() {
         @Override
-        boolean isApplicable(MethodType callSiteType, MethodHandle method) {
-            final MethodType methodType = method.type();
+        boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+            final MethodType methodType = method.getMethodType();
             final int methodArity = methodType.parameterCount();
             if(methodArity != callSiteType.parameterCount()) {
                 return false;
@@ -166,8 +165,8 @@
      */
     static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() {
         @Override
-        boolean isApplicable(MethodType callSiteType, MethodHandle method) {
-            final MethodType methodType = method.type();
+        boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+            final MethodType methodType = method.getMethodType();
             final int methodArity = methodType.parameterCount();
             if(methodArity != callSiteType.parameterCount()) {
                 return false;
@@ -189,11 +188,11 @@
      */
     static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() {
         @Override
-        boolean isApplicable(MethodType callSiteType, MethodHandle method) {
-            if(!method.isVarargsCollector()) {
+        boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
+            if(!method.isVarArgs()) {
                 return false;
             }
-            final MethodType methodType = method.type();
+            final MethodType methodType = method.getMethodType();
             final int methodArity = methodType.parameterCount();
             final int fixArity = methodArity - 1;
             final int callSiteArity = callSiteType.parameterCount();
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java
--- a/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/BeansLinker.java	Mon Jul 22 17:40:26 2013 -0700
@@ -84,6 +84,8 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.Collections;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.DynamicLinkerFactory;
 import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -166,6 +168,72 @@
         return obj instanceof DynamicMethod;
     }
 
+    /**
+     * Returns a collection of names of all readable instance properties of a class.
+     * @param clazz the class
+     * @return a collection of names of all readable instance properties of a class.
+     */
+    public static Collection getReadableInstancePropertyNames(Class clazz) {
+        TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+        if(linker instanceof BeanLinker) {
+            return ((BeanLinker)linker).getReadablePropertyNames();
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Returns a collection of names of all writable instance properties of a class.
+     * @param clazz the class
+     * @return a collection of names of all writable instance properties of a class.
+     */
+    public static Collection getWritableInstancePropertyNames(Class clazz) {
+        TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+        if(linker instanceof BeanLinker) {
+            return ((BeanLinker)linker).getWritablePropertyNames();
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Returns a collection of names of all instance methods of a class.
+     * @param clazz the class
+     * @return a collection of names of all instance methods of a class.
+     */
+    public static Collection getInstanceMethodNames(Class clazz) {
+        TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
+        if(linker instanceof BeanLinker) {
+            return ((BeanLinker)linker).getMethodNames();
+        }
+        return Collections.emptySet();
+    }
+
+    /**
+     * Returns a collection of names of all readable static properties of a class.
+     * @param clazz the class
+     * @return a collection of names of all readable static properties of a class.
+     */
+    public static Collection getReadableStaticPropertyNames(Class clazz) {
+        return StaticClassLinker.getReadableStaticPropertyNames(clazz);
+    }
+
+    /**
+     * Returns a collection of names of all writable static properties of a class.
+     * @param clazz the class
+     * @return a collection of names of all writable static properties of a class.
+     */
+    public static Collection getWritableStaticPropertyNames(Class clazz) {
+        return StaticClassLinker.getWritableStaticPropertyNames(clazz);
+    }
+
+    /**
+     * Returns a collection of names of all static methods of a class.
+     * @param clazz the class
+     * @return a collection of names of all static methods of a class.
+     */
+    public static Collection getStaticMethodNames(Class clazz) {
+        return StaticClassLinker.getStaticMethodNames(clazz);
+    }
+
     @Override
     public GuardedInvocation getGuardedInvocation(LinkRequest request, final LinkerServices linkerServices)
             throws Exception {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java	Mon Jul 22 17:40:26 2013 -0700
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2009-2013 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import sun.reflect.CallerSensitive;
+
+/**
+ * Utility class that determines if a method or constructor is caller sensitive. It actually encapsulates two different
+ * strategies for determining caller sensitivity; a more robust one that works if Dynalink runs as code with access
+ * to {@code sun.reflect} package, and an unprivileged one that is used when Dynalink doesn't have access to that
+ * package. Note that even the unprivileged strategy is ordinarily robust, but it relies on the {@code toString} method
+ * of the annotation. If an attacker were to use a different annotation to spoof the string representation of the
+ * {@code CallerSensitive} annotation, they could designate their own methods as caller sensitive. This however does not
+ * escalate privileges, only causes Dynalink to never cache method handles for such methods, so all it would do would
+ * decrease the performance in linking such methods. In the opposite case when an attacker could trick Dynalink into not
+ * recognizing genuine {@code CallerSensitive} annotations, Dynalink would treat caller sensitive methods as ordinary
+ * methods, and would cache them bound to a zero-privilege delegate as the caller (just what Dynalink did before it
+ * could handle caller-sensitive methods). That would practically render caller-sensitive methods exposed through
+ * Dynalink unusable, but again, can not lead to any privilege escalations. Therefore, even the less robust unprivileged
+ * strategy is safe; the worst thing a successful attack against it can achieve is slight reduction in Dynalink-exposed
+ * functionality or performance.
+ */
+public class CallerSensitiveDetector {
+
+    private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy();
+
+    static boolean isCallerSensitive(AccessibleObject ao) {
+        return DETECTION_STRATEGY.isCallerSensitive(ao);
+    }
+
+    private static DetectionStrategy getDetectionStrategy() {
+        try {
+            return new PrivilegedDetectionStrategy();
+        } catch(Throwable t) {
+            return new UnprivilegedDetectionStrategy();
+        }
+    }
+
+    private abstract static class DetectionStrategy {
+        abstract boolean isCallerSensitive(AccessibleObject ao);
+    }
+
+    private static class PrivilegedDetectionStrategy extends DetectionStrategy {
+        private static final Class CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class;
+
+        @Override
+        boolean isCallerSensitive(AccessibleObject ao) {
+            return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null;
+        }
+    }
+
+    private static class UnprivilegedDetectionStrategy extends DetectionStrategy {
+        private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()";
+
+        @Override
+        boolean isCallerSensitive(AccessibleObject o) {
+            for(Annotation a: o.getAnnotations()) {
+                if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2009-2013 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import jdk.internal.dynalink.support.Lookup;
+
+/**
+ * A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is
+ * caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in
+ * {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on
+ * every request.
+ *
+ * @author Attila Szegedi
+ */
+class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
+    // Typed as "AccessibleObject" as it can be either a method or a constructor.
+    // If we were Java8-only, we could use java.lang.reflect.Executable
+    private final AccessibleObject target;
+    private final MethodType type;
+
+    public CallerSensitiveDynamicMethod(AccessibleObject target) {
+        super(getName(target));
+        this.target = target;
+        this.type = getMethodType(target);
+    }
+
+    private static String getName(AccessibleObject target) {
+        final Member m = (Member)target;
+        return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
+                m.getName()));
+    }
+
+    @Override
+    MethodType getMethodType() {
+        return type;
+    }
+
+    private static MethodType getMethodType(AccessibleObject ao) {
+        final boolean isMethod = ao instanceof Method;
+        final Class rtype = isMethod ? ((Method)ao).getReturnType() : ((Constructor)ao).getDeclaringClass();
+        final Class[] ptypes = isMethod ? ((Method)ao).getParameterTypes() : ((Constructor)ao).getParameterTypes();
+        final MethodType type = MethodType.methodType(rtype, ptypes);
+        final Member m = (Member)ao;
+        return type.insertParameterTypes(0,
+                isMethod ?
+                        Modifier.isStatic(m.getModifiers()) ?
+                                Object.class :
+                                m.getDeclaringClass() :
+                        StaticClass.class);
+    }
+
+    @Override
+    boolean isVarArgs() {
+        return target instanceof Method ? ((Method)target).isVarArgs() : ((Constructor)target).isVarArgs();
+    }
+
+    @Override
+    MethodHandle getTarget(MethodHandles.Lookup lookup) {
+        if(target instanceof Method) {
+            final MethodHandle mh = Lookup.unreflect(lookup, (Method)target);
+            if(Modifier.isStatic(((Member)target).getModifiers())) {
+                return StaticClassIntrospector.editStaticMethodHandle(mh);
+            }
+            return mh;
+        }
+        return StaticClassIntrospector.editConstructorMethodHandle(Lookup.unreflectConstructor(lookup,
+                (Constructor)target));
+    }
+}
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/ClassString.java
--- a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java	Mon Jul 22 17:40:26 2013 -0700
@@ -155,8 +155,8 @@
     }
 
     List getMaximallySpecifics(List methods, LinkerServices linkerServices, boolean varArg) {
-        return MaximallySpecific.getMaximallySpecificMethods(getApplicables(methods, linkerServices, varArg), varArg,
-                classes, linkerServices);
+        return MaximallySpecific.getMaximallySpecificMethodHandles(getApplicables(methods, linkerServices, varArg),
+                varArg, classes, linkerServices);
     }
 
     /**
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java
--- a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -84,8 +84,7 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
-import java.util.StringTokenizer;
+import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.LinkerServices;
 
 /**
@@ -116,45 +115,28 @@
      * is a variable arguments (vararg) method, it will pack the extra arguments in an array before the invocation of
      * the underlying method if it is not already done.
      *
-     * @param callSiteType the method type at a call site
+     * @param callSiteDescriptor the descriptor of the call site
      * @param linkerServices linker services. Used for language-specific type conversions.
      * @return an invocation suitable for calling the method from the specified call site.
      */
-    abstract MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices);
+    abstract MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices);
 
     /**
-     * Returns a simple dynamic method representing a single underlying Java method (possibly selected among several
+     * Returns a single dynamic method representing a single underlying Java method (possibly selected among several
      * overloads) with formal parameter types exactly matching the passed signature.
      * @param paramTypes the comma-separated list of requested parameter type names. The names will match both
      * qualified and unqualified type names.
-     * @return a simple dynamic method representing a single underlying Java method, or null if none of the Java methods
+     * @return a single dynamic method representing a single underlying Java method, or null if none of the Java methods
      * behind this dynamic method exactly match the requested parameter types.
      */
-    abstract SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes);
+    abstract SingleDynamicMethod getMethodForExactParamTypes(String paramTypes);
 
     /**
-     * True if this dynamic method already contains a method handle with an identical signature as the passed in method
-     * handle.
-     * @param mh the method handle to check
-     * @return true if it already contains an equivalent method handle.
+     * True if this dynamic method already contains a method with an identical signature as the passed in method.
+     * @param method the method to check
+     * @return true if it already contains an equivalent method.
      */
-    abstract boolean contains(MethodHandle mh);
-
-    static boolean typeMatchesDescription(String paramTypes, MethodType type) {
-        final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
-        for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
-            if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
-                return false;
-            }
-        }
-        return !tok.hasMoreTokens();
-    }
-
-    private static boolean typeNameMatches(String typeName, Class type) {
-        final int lastDot = typeName.lastIndexOf('.');
-        final String fullTypeName = type.getCanonicalName();
-        return lastDot != -1 && fullTypeName.endsWith(typeName.substring(lastDot)) || typeName.equals(fullTypeName);
-    }
+    abstract boolean contains(SingleDynamicMethod method);
 
     static String getClassAndMethodName(Class clazz, String name) {
         final String clazzName = clazz.getCanonicalName();
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java
--- a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java	Mon Jul 22 17:40:26 2013 -0700
@@ -85,12 +85,12 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
+import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
 import jdk.internal.dynalink.support.Guards;
 
 /**
@@ -110,19 +110,18 @@
             return null;
         }
         final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
-        if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn")  {
+        if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
             return null;
         }
         final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
         if(operator == "call") {
-            final MethodType type = desc.getMethodType();
-            final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(type.dropParameterTypes(0, 1),
-                    linkerServices);
+            final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(
+                    CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
             if(invocation == null) {
                 return null;
             }
-            return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0, type.parameterType(0)),
-                    Guards.getIdentityGuard(receiver));
+            return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
+                    desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
         }
         return null;
     }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java
--- a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java	Mon Jul 22 17:40:26 2013 -0700
@@ -167,10 +167,6 @@
         return editMethodHandle(SafeUnreflector.unreflectSetter(field));
     }
 
-    MethodHandle unreflect(Method method) {
-        return editMethodHandle(SafeUnreflector.unreflect(method));
-    }
-
     /**
      * Returns an edited method handle. A facet might need to edit an unreflected method handle before it is usable with
      * the facet. By default, returns the passed method handle unchanged. The class' static facet will introduce a
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java
--- a/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java	Mon Jul 22 17:40:26 2013 -0700
@@ -105,10 +105,58 @@
      * @param varArgs whether to assume the methods are varargs
      * @return the list of maximally specific methods.
      */
-    static List getMaximallySpecificMethods(List methods, boolean varArgs) {
-        return getMaximallySpecificMethods(methods, varArgs, null, null);
+    static List getMaximallySpecificMethods(List methods, boolean varArgs) {
+        return getMaximallySpecificSingleDynamicMethods(methods, varArgs, null, null);
+    }
+
+    private abstract static class MethodTypeGetter {
+        abstract MethodType getMethodType(T t);
     }
 
+    private static final MethodTypeGetter METHOD_HANDLE_TYPE_GETTER =
+            new MethodTypeGetter() {
+        @Override
+        MethodType getMethodType(MethodHandle t) {
+            return t.type();
+        }
+    };
+
+    private static final MethodTypeGetter DYNAMIC_METHOD_TYPE_GETTER =
+            new MethodTypeGetter() {
+        @Override
+        MethodType getMethodType(SingleDynamicMethod t) {
+            return t.getMethodType();
+        }
+    };
+
+     /**
+      * Given a list of methods handles, returns a list of maximally specific methods, applying language-runtime
+      * specific conversion preferences.
+      *
+      * @param methods the list of method handles
+      * @param varArgs whether to assume the method handles are varargs
+      * @param argTypes concrete argument types for the invocation
+      * @return the list of maximally specific method handles.
+      */
+     static List getMaximallySpecificMethodHandles(List methods, boolean varArgs,
+             Class[] argTypes, LinkerServices ls) {
+         return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, METHOD_HANDLE_TYPE_GETTER);
+     }
+
+     /**
+      * Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
+      * conversion preferences.
+      *
+      * @param methods the list of methods
+      * @param varArgs whether to assume the methods are varargs
+      * @param argTypes concrete argument types for the invocation
+      * @return the list of maximally specific methods.
+      */
+     static List getMaximallySpecificSingleDynamicMethods(List methods,
+             boolean varArgs, Class[] argTypes, LinkerServices ls) {
+         return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, DYNAMIC_METHOD_TYPE_GETTER);
+     }
+
     /**
      * Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
      * conversion preferences.
@@ -118,18 +166,18 @@
      * @param argTypes concrete argument types for the invocation
      * @return the list of maximally specific methods.
      */
-    static List getMaximallySpecificMethods(List methods, boolean varArgs,
-            Class[] argTypes, LinkerServices ls) {
+    private static  List getMaximallySpecificMethods(List methods, boolean varArgs,
+            Class[] argTypes, LinkerServices ls, MethodTypeGetter methodTypeGetter) {
         if(methods.size() < 2) {
             return methods;
         }
-        final LinkedList maximals = new LinkedList<>();
-        for(MethodHandle m: methods) {
-            final MethodType methodType = m.type();
+        final LinkedList maximals = new LinkedList<>();
+        for(T m: methods) {
+            final MethodType methodType = methodTypeGetter.getMethodType(m);
             boolean lessSpecific = false;
-            for(Iterator maximal = maximals.iterator(); maximal.hasNext();) {
-                final MethodHandle max = maximal.next();
-                switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) {
+            for(Iterator maximal = maximals.iterator(); maximal.hasNext();) {
+                final T max = maximal.next();
+                switch(isMoreSpecific(methodType, methodTypeGetter.getMethodType(max), varArgs, argTypes, ls)) {
                     case TYPE_1_BETTER: {
                         maximal.remove();
                         break;
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
--- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -84,16 +84,21 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.support.TypeUtilities;
 
 /**
- * Represents an overloaded method.
+ * Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all
+ * constructors) for a particular class. Correctly handles overload resolution, variable arity methods, and caller
+ * sensitive methods within the overloads.
  *
  * @author Attila Szegedi
  */
@@ -101,7 +106,7 @@
     /**
      * Holds a list of all methods.
      */
-    private final LinkedList methods;
+    private final LinkedList methods;
     private final ClassLoader classLoader;
 
     /**
@@ -111,21 +116,22 @@
      * @param name the name of the method
      */
     OverloadedDynamicMethod(Class clazz, String name) {
-        this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
+        this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
     }
 
-    private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) {
+    private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) {
         super(name);
         this.methods = methods;
         this.classLoader = classLoader;
     }
 
     @Override
-    SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
-        final LinkedList matchingMethods = new LinkedList<>();
-        for(MethodHandle method: methods) {
-            if(typeMatchesDescription(paramTypes, method.type())) {
-                matchingMethods.add(method);
+    SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
+        final LinkedList matchingMethods = new LinkedList<>();
+        for(SingleDynamicMethod method: methods) {
+            final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes);
+            if(matchingMethod != null) {
+                matchingMethods.add(matchingMethod);
             }
         }
         switch(matchingMethods.size()) {
@@ -133,8 +139,7 @@
                 return null;
             }
             case 1: {
-                final MethodHandle target = matchingMethods.get(0);
-                return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName()));
+                return matchingMethods.getFirst();
             }
             default: {
                 throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types "
@@ -144,7 +149,8 @@
     }
 
     @Override
-    public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) {
+    public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
+        final MethodType callSiteType = callSiteDescriptor.getMethodType();
         // First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2)
         final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType,
                 ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING);
@@ -156,7 +162,7 @@
                 ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY);
 
         // Find the methods that are maximally specific based on the call site signature
-        List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
+        List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
         if(maximallySpecifics.isEmpty()) {
             maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods();
             if(maximallySpecifics.isEmpty()) {
@@ -171,12 +177,12 @@
         // (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability
         // rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation.
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        final List invokables = (List)methods.clone();
+        final List invokables = (List)methods.clone();
         invokables.removeAll(subtypingApplicables.getMethods());
         invokables.removeAll(methodInvocationApplicables.getMethods());
         invokables.removeAll(variableArityApplicables.getMethods());
-        for(final Iterator it = invokables.iterator(); it.hasNext();) {
-            final MethodHandle m = it.next();
+        for(final Iterator it = invokables.iterator(); it.hasNext();) {
+            final SingleDynamicMethod m = it.next();
             if(!isApplicableDynamically(linkerServices, callSiteType, m)) {
                 it.remove();
             }
@@ -199,54 +205,45 @@
             }
             case 1: {
                 // Very lucky, we ended up with a single candidate method handle based on the call site signature; we
-                // can link it very simply by delegating to a SimpleDynamicMethod.
-                final MethodHandle mh = invokables.iterator().next();
-                return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices);
+                // can link it very simply by delegating to the SingleDynamicMethod.
+                invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices);
             }
             default: {
                 // We have more than one candidate. We have no choice but to link to a method that resolves overloads on
                 // every invocation (alternatively, we could opportunistically link the one method that resolves for the
                 // current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd
-                // go back all the way to candidate selection.
-                // TODO: cache per call site type
-                return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker();
+                // go back all the way to candidate selection. Note that we're resolving any potential caller sensitive
+                // methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
+                // has an already determined Lookup.
+                final List methodHandles = new ArrayList<>(invokables.size());
+                final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
+                for(SingleDynamicMethod method: invokables) {
+                    methodHandles.add(method.getTarget(lookup));
+                }
+                return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
             }
         }
 
     }
 
     @Override
-    public boolean contains(MethodHandle mh) {
-        final MethodType type = mh.type();
-        for(MethodHandle method: methods) {
-            if(typesEqualNoReceiver(type, method.type())) {
+    public boolean contains(SingleDynamicMethod m) {
+        for(SingleDynamicMethod method: methods) {
+            if(method.contains(m)) {
                 return true;
             }
         }
         return false;
     }
 
-    private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) {
-        final int pc = type1.parameterCount();
-        if(pc != type2.parameterCount()) {
-            return false;
-        }
-        for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver
-            if(type1.parameterType(i) != type2.parameterType(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     ClassLoader getClassLoader() {
         return classLoader;
     }
 
     private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType,
-            MethodHandle m) {
-        final MethodType methodType = m.type();
-        final boolean varArgs = m.isVarargsCollector();
+            SingleDynamicMethod m) {
+        final MethodType methodType = m.getMethodType();
+        final boolean varArgs = m.isVarArgs();
         final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
         final int callSiteArgLen = callSiteType.parameterCount();
 
@@ -301,20 +298,11 @@
     }
 
     /**
-     * Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set.
-     *
-     * @param method the method to add.
-     */
-    void addMethod(SimpleDynamicMethod method) {
-        addMethod(method.getTarget());
-    }
-
-    /**
      * Add a method to this overloaded method's set.
      *
      * @param method a method to add
      */
-    public void addMethod(MethodHandle method) {
+    public void addMethod(SingleDynamicMethod method) {
         methods.add(method);
     }
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java
--- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -135,7 +135,7 @@
         varArgMethods.trimToSize();
 
         final MethodHandle bound = SELECT_METHOD.bindTo(this);
-        final MethodHandle collecting = SimpleDynamicMethod.collectArguments(bound, argNum).asType(
+        final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
                 callSiteType.changeReturnType(MethodHandle.class));
         invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting);
     }
@@ -167,7 +167,7 @@
                     break;
                 }
                 case 1: {
-                    method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices);
+                    method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices);
                     break;
                 }
                 default: {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
--- a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -84,29 +84,22 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.lang.reflect.Array;
-import jdk.internal.dynalink.linker.LinkerServices;
-import jdk.internal.dynalink.support.Guards;
 
 /**
- * A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs.
+ * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
+ * not caller sensitive, this class pre-caches its method handle and always returns it from the call to
+ * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
+ * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
+ * getters/setters, etc.
  *
  * @author Attila Szegedi
  */
-class SimpleDynamicMethod extends DynamicMethod {
+class SimpleDynamicMethod extends SingleDynamicMethod {
     private final MethodHandle target;
 
     /**
-     * Creates a simple dynamic method with no name.
-     * @param target the target method handle
-     */
-    SimpleDynamicMethod(MethodHandle target) {
-        this(target, null);
-    }
-
-    /**
      * Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
      * signature.
      *
@@ -115,125 +108,26 @@
      * @param name the simple name of the method
      */
     SimpleDynamicMethod(MethodHandle target, Class clazz, String name) {
-        this(target, getName(target, clazz, name));
-    }
-
-    SimpleDynamicMethod(MethodHandle target, String name) {
-        super(name);
+        super(getName(target, clazz, name));
         this.target = target;
     }
 
     private static String getName(MethodHandle target, Class clazz, String name) {
-        return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name));
-    }
-
-    static String getMethodNameWithSignature(MethodHandle target, String methodName) {
-        final String typeStr = target.type().toString();
-        final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
-        int secondParamIndex = typeStr.indexOf(',') + 1;
-        if(secondParamIndex == 0) {
-            secondParamIndex = retTypeIndex - 1;
-        }
-        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
-    }
-
-    /**
-     * Returns the target of this dynamic method
-     *
-     * @return the target of this dynamic method
-     */
-    MethodHandle getTarget() {
-        return target;
+        return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
     }
 
     @Override
-    SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
-        return typeMatchesDescription(paramTypes, target.type()) ? this : null;
+    boolean isVarArgs() {
+        return target.isVarargsCollector();
     }
 
     @Override
-    MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) {
-        final MethodType methodType = target.type();
-        final int paramsLen = methodType.parameterCount();
-        final boolean varArgs = target.isVarargsCollector();
-        final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
-        final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
-        final int argsLen = callSiteType.parameterCount();
-        if(argsLen < fixParamsLen) {
-            // Less actual arguments than number of fixed declared arguments; can't invoke.
-            return null;
-        }
-        // Method handle has the same number of fixed arguments as the call site type
-        if(argsLen == fixParamsLen) {
-            // Method handle that matches the number of actual arguments as the number of fixed arguments
-            final MethodHandle matchedMethod;
-            if(varArgs) {
-                // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
-                // arguments.
-                matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
-                        methodType.parameterType(fixParamsLen).getComponentType(), 0));
-            } else {
-                // Otherwise, just use the method
-                matchedMethod = fixTarget;
-            }
-            return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
-        }
-
-        // What's below only works for varargs
-        if(!varArgs) {
-            return null;
-        }
-
-        final Class varArgType = methodType.parameterType(fixParamsLen);
-        // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
-        // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
-        if(argsLen == paramsLen) {
-            final Class callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
-            if(varArgType.isAssignableFrom(callSiteLastArgType)) {
-                // Call site signature guarantees we'll always be passed a single compatible array; just link directly
-                // to the method.
-                return createConvertingInvocation(fixTarget, linkerServices, callSiteType);
-            }
-            if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
-                // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
-                // link immediately to a vararg-packing method handle.
-                return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
-            }
-            // Call site signature makes no guarantees that the single argument in the vararg position will be
-            // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
-            // method when it is not.
-            return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
-                    createConvertingInvocation(fixTarget, linkerServices, callSiteType),
-                    createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
-        }
-
-        // Remaining case: more than one vararg.
-        return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+    MethodType getMethodType() {
+        return target.type();
     }
 
     @Override
-    public boolean contains(MethodHandle mh) {
-        return target.type().parameterList().equals(mh.type().parameterList());
-    }
-
-    /**
-     * Creates a method handle out of the original target that will collect the varargs for the exact component type of
-     * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
-     * for which it is necessary when later passed to linkerServices.convertArguments().
-     *
-     * @param target the original method handle
-     * @param parameterCount the total number of arguments in the new method handle
-     * @return a collecting method handle
-     */
-    static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
-        final MethodType methodType = target.type();
-        final int fixParamsLen = methodType.parameterCount() - 1;
-        final Class arrayType = methodType.parameterType(fixParamsLen);
-        return target.asCollector(arrayType, parameterCount - fixParamsLen);
-    }
-
-    private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
-            final LinkerServices linkerServices, final MethodType callSiteType) {
-        return linkerServices.asType(sizedMethod, callSiteType);
+    MethodHandle getTarget(Lookup lookup) {
+        return target;
     }
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Mon Jul 22 17:40:26 2013 -0700
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file, and Oracle licenses the original version of this file under the BSD
+ * license:
+ */
+/*
+   Copyright 2009-2013 Attila Szegedi
+
+   Licensed under both the Apache License, Version 2.0 (the "Apache License")
+   and the BSD License (the "BSD License"), with licensee being free to
+   choose either of the two at their discretion.
+
+   You may not use this file except in compliance with either the Apache
+   License or the BSD License.
+
+   If you choose to use this file in compliance with the Apache License, the
+   following notice applies to you:
+
+       You may obtain a copy of the Apache License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing, software
+       distributed under the License is distributed on an "AS IS" BASIS,
+       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+       implied. See the License for the specific language governing
+       permissions and limitations under the License.
+
+   If you choose to use this file in compliance with the BSD License, the
+   following notice applies to you:
+
+       Redistribution and use in source and binary forms, with or without
+       modification, are permitted provided that the following conditions are
+       met:
+       * Redistributions of source code must retain the above copyright
+         notice, this list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright
+         notice, this list of conditions and the following disclaimer in the
+         documentation and/or other materials provided with the distribution.
+       * Neither the name of the copyright holder nor the names of
+         contributors may be used to endorse or promote products derived from
+         this software without specific prior written permission.
+
+       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
+       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package jdk.internal.dynalink.beans;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Array;
+import java.util.StringTokenizer;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkerServices;
+import jdk.internal.dynalink.support.Guards;
+
+/**
+ * Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
+ * target method to a call site type (including mapping variable arity methods to a call site signature with different
+ * arity).
+ * @author Attila Szegedi
+ * @version $Id: $
+ */
+abstract class SingleDynamicMethod extends DynamicMethod {
+    SingleDynamicMethod(String name) {
+        super(name);
+    }
+
+    /**
+     * Returns true if this method is variable arity.
+     * @return true if this method is variable arity.
+     */
+    abstract boolean isVarArgs();
+
+    /**
+     * Returns this method's native type.
+     * @return this method's native type.
+     */
+    abstract MethodType getMethodType();
+
+    /**
+     * Given a specified lookup, returns a method handle to this method's target.
+     * @param lookup the lookup to use.
+     * @return the handle to this method's target method.
+     */
+    abstract MethodHandle getTarget(MethodHandles.Lookup lookup);
+
+    @Override
+    MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
+        return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(),
+                linkerServices);
+    }
+
+    @Override
+    SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
+        return typeMatchesDescription(paramTypes, getMethodType()) ? this : null;
+    }
+
+    @Override
+    boolean contains(SingleDynamicMethod method) {
+        return getMethodType().parameterList().equals(method.getMethodType().parameterList());
+    }
+
+    static String getMethodNameWithSignature(MethodType type, String methodName) {
+        final String typeStr = type.toString();
+        final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
+        int secondParamIndex = typeStr.indexOf(',') + 1;
+        if(secondParamIndex == 0) {
+            secondParamIndex = retTypeIndex - 1;
+        }
+        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
+    }
+
+    /**
+     * Given a method handle and a call site type, adapts the method handle to the call site type. Performs type
+     * conversions as needed using the specified linker services, and in case that the method handle is a vararg
+     * collector, matches it to the arity of the call site.
+     * @param target the method handle to adapt
+     * @param callSiteType the type of the call site
+     * @param linkerServices the linker services used for type conversions
+     * @return the adapted method handle.
+     */
+    static MethodHandle getInvocation(MethodHandle target, MethodType callSiteType, LinkerServices linkerServices) {
+        final MethodType methodType = target.type();
+        final int paramsLen = methodType.parameterCount();
+        final boolean varArgs = target.isVarargsCollector();
+        final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
+        final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
+        final int argsLen = callSiteType.parameterCount();
+        if(argsLen < fixParamsLen) {
+            // Less actual arguments than number of fixed declared arguments; can't invoke.
+            return null;
+        }
+        // Method handle has the same number of fixed arguments as the call site type
+        if(argsLen == fixParamsLen) {
+            // Method handle that matches the number of actual arguments as the number of fixed arguments
+            final MethodHandle matchedMethod;
+            if(varArgs) {
+                // If vararg, add a zero-length array of the expected type as the last argument to signify no variable
+                // arguments.
+                matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
+                        methodType.parameterType(fixParamsLen).getComponentType(), 0));
+            } else {
+                // Otherwise, just use the method
+                matchedMethod = fixTarget;
+            }
+            return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
+        }
+
+        // What's below only works for varargs
+        if(!varArgs) {
+            return null;
+        }
+
+        final Class varArgType = methodType.parameterType(fixParamsLen);
+        // Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
+        // must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
+        if(argsLen == paramsLen) {
+            final Class callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
+            if(varArgType.isAssignableFrom(callSiteLastArgType)) {
+                // Call site signature guarantees we'll always be passed a single compatible array; just link directly
+                // to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
+                return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
+                        callSiteLastArgType);
+            }
+            if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
+                // Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
+                // link immediately to a vararg-packing method handle.
+                return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+            }
+            // Call site signature makes no guarantees that the single argument in the vararg position will be
+            // compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
+            // method when it is not.
+            return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
+                    createConvertingInvocation(fixTarget, linkerServices, callSiteType),
+                    createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
+        }
+
+        // Remaining case: more than one vararg.
+        return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
+    }
+
+    /**
+     * Creates a method handle out of the original target that will collect the varargs for the exact component type of
+     * the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
+     * for which it is necessary when later passed to linkerServices.convertArguments().
+     *
+     * @param target the original method handle
+     * @param parameterCount the total number of arguments in the new method handle
+     * @return a collecting method handle
+     */
+    static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
+        final MethodType methodType = target.type();
+        final int fixParamsLen = methodType.parameterCount() - 1;
+        final Class arrayType = methodType.parameterType(fixParamsLen);
+        return target.asCollector(arrayType, parameterCount - fixParamsLen);
+    }
+
+    private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
+            final LinkerServices linkerServices, final MethodType callSiteType) {
+        return linkerServices.asType(sizedMethod, callSiteType);
+    }
+
+    private static boolean typeMatchesDescription(String paramTypes, MethodType type) {
+        final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
+        for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
+            if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
+                return false;
+            }
+        }
+        return !tok.hasMoreTokens();
+    }
+
+    private static boolean typeNameMatches(String typeName, Class type) {
+        return  typeName.equals(typeName.indexOf('.') == -1 ? type.getSimpleName() : type.getCanonicalName());
+    }
+}
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java	Mon Jul 22 17:40:26 2013 -0700
@@ -106,10 +106,18 @@
 
     @Override
     MethodHandle editMethodHandle(MethodHandle mh) {
+        return editStaticMethodHandle(mh);
+    }
+
+    static MethodHandle editStaticMethodHandle(MethodHandle mh) {
         return dropReceiver(mh, Object.class);
     }
 
-    static MethodHandle dropReceiver(final MethodHandle mh, final Class receiverClass) {
+    static MethodHandle editConstructorMethodHandle(MethodHandle cmh) {
+        return dropReceiver(cmh, StaticClass.class);
+    }
+
+    private static MethodHandle dropReceiver(final MethodHandle mh, final Class receiverClass) {
         MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
         // NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
         if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java
--- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java	Mon Jul 22 17:40:26 2013 -0700
@@ -87,13 +87,11 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
+import java.util.Collection;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
 import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.GuardingDynamicLinker;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
@@ -104,9 +102,9 @@
  * @author Attila Szegedi
  */
 class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
-    private final ClassValue linkers = new ClassValue() {
+    private static final ClassValue linkers = new ClassValue() {
         @Override
-        protected GuardingDynamicLinker computeValue(Class clazz) {
+        protected SingleClassStaticsLinker computeValue(Class clazz) {
             return new SingleClassStaticsLinker(clazz);
         }
     };
@@ -131,20 +129,11 @@
         private static DynamicMethod createConstructorMethod(Class clazz) {
             if(clazz.isArray()) {
                 final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType());
-                return new SimpleDynamicMethod(drop(boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(
-                        clazz))), clazz, "");
+                return new SimpleDynamicMethod(StaticClassIntrospector.editConstructorMethodHandle(
+                        boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(clazz))), clazz, "");
             }
 
-            final Constructor[] ctrs = clazz.getConstructors();
-            final List mhs = new ArrayList<>(ctrs.length);
-            for(int i = 0; i < ctrs.length; ++i) {
-                mhs.add(drop(SafeUnreflector.unreflectConstructor(ctrs[i])));
-            }
-            return createDynamicMethod(mhs, clazz, "");
-        }
-
-        private static MethodHandle drop(MethodHandle mh) {
-            return StaticClassIntrospector.dropReceiver(mh, StaticClass.class);
+            return createDynamicMethod(Arrays.asList(clazz.getConstructors()), clazz, "");
         }
 
         @Override
@@ -161,17 +150,28 @@
             }
             final CallSiteDescriptor desc = request.getCallSiteDescriptor();
             final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR);
-            final MethodType methodType = desc.getMethodType();
             if("new" == op && constructor != null) {
-                final MethodHandle ctorInvocation = constructor.getInvocation(methodType, linkerServices);
+                final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices);
                 if(ctorInvocation != null) {
-                    return new GuardedInvocation(ctorInvocation, getClassGuard(methodType));
+                    return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType()));
                 }
             }
             return null;
         }
     }
 
+    static Collection getReadableStaticPropertyNames(Class clazz) {
+        return linkers.get(clazz).getReadablePropertyNames();
+    }
+
+    static Collection getWritableStaticPropertyNames(Class clazz) {
+        return linkers.get(clazz).getWritablePropertyNames();
+    }
+
+    static Collection getStaticMethodNames(Class clazz) {
+        return linkers.get(clazz).getMethodNames();
+    }
+
     @Override
     public GuardedInvocation getGuardedInvocation(LinkRequest request, LinkerServices linkerServices) throws Exception {
         final Object receiver = request.getReceiver();
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
--- a/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Mon Jul 22 17:40:26 2013 -0700
@@ -139,8 +139,9 @@
 
     @Override
     public int hashCode() {
+        final MethodHandles.Lookup lookup = getLookup();
+        int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
         final int c = getNameTokenCount();
-        int h = 0;
         for(int i = 0; i < c; ++i) {
             h = h * 31 + getNameToken(i).hashCode();
         }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/internal/dynalink/support/Lookup.java
--- a/nashorn/src/jdk/internal/dynalink/support/Lookup.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java	Mon Jul 22 17:40:26 2013 -0700
@@ -122,6 +122,18 @@
      * @return the unreflected method handle.
      */
     public MethodHandle unreflect(Method m) {
+        return unreflect(lookup, m);
+    }
+
+    /**
+     * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered
+     * {@link IllegalAccessException} into an {@link IllegalAccessError}.
+     *
+     * @param lookup the lookup used to unreflect
+     * @param m the method to unreflect
+     * @return the unreflected method handle.
+     */
+    public static MethodHandle unreflect(MethodHandles.Lookup lookup, Method m) {
         try {
             return lookup.unreflect(m);
         } catch(IllegalAccessException e) {
@@ -131,7 +143,6 @@
         }
     }
 
-
     /**
      * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered
      * {@link IllegalAccessException} into an {@link IllegalAccessError}.
@@ -202,6 +213,18 @@
      * @return the unreflected constructor handle.
      */
     public MethodHandle unreflectConstructor(Constructor c) {
+        return unreflectConstructor(lookup, c);
+    }
+
+    /**
+     * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any
+     * encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
+     *
+     * @param lookup the lookup used to unreflect
+     * @param c the constructor to unreflect
+     * @return the unreflected constructor handle.
+     */
+    public static MethodHandle unreflectConstructor(MethodHandles.Lookup lookup, Constructor c) {
         try {
             return lookup.unreflectConstructor(c);
         } catch(IllegalAccessException e) {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/api/scripting/NashornException.java
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java	Mon Jul 22 17:40:26 2013 -0700
@@ -146,7 +146,7 @@
      * @return array of javascript stack frames
      */
     public static StackTraceElement[] getScriptFrames(final Throwable exception) {
-        final StackTraceElement[] frames = ((Throwable)exception).getStackTrace();
+        final StackTraceElement[] frames = exception.getStackTrace();
         final List filtered = new ArrayList<>();
         for (final StackTraceElement st : frames) {
             if (ECMAErrors.isScriptFrame(st)) {
@@ -170,7 +170,7 @@
      */
     public static String getScriptStackString(final Throwable exception) {
         final StringBuilder buf = new StringBuilder();
-        final StackTraceElement[] frames = getScriptFrames((Throwable)exception);
+        final StackTraceElement[] frames = getScriptFrames(exception);
         for (final StackTraceElement st : frames) {
             buf.append("\tat ");
             buf.append(st.getMethodName());
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java	Mon Jul 22 17:40:26 2013 -0700
@@ -33,6 +33,7 @@
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.security.AccessController;
@@ -184,6 +185,19 @@
     }
 
     private  T getInterfaceInner(final Object self, final Class clazz) {
+        if (clazz == null || !clazz.isInterface()) {
+            throw new IllegalArgumentException("interface Class expected");
+        }
+
+        // perform security access check as early as possible
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (! Modifier.isPublic(clazz.getModifiers())) {
+                throw new SecurityException("attempt to implement non-public interfce: " + clazz);
+            }
+            Context.checkPackageAccess(clazz.getName());
+        }
+
         final ScriptObject realSelf;
         final ScriptObject ctxtGlobal = getNashornGlobalFrom(context);
         if(self == null) {
@@ -193,6 +207,7 @@
         } else {
             realSelf = (ScriptObject)self;
         }
+
         try {
             final ScriptObject oldGlobal = getNashornGlobal();
             try {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Mon Jul 22 17:40:26 2013 -0700
@@ -52,11 +52,6 @@
     private final ScriptObject sobj;
     private final ScriptObject global;
 
-    ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
-        this.sobj = sobj;
-        this.global = global;
-    }
-
     @Override
     public boolean equals(final Object other) {
         if (other instanceof ScriptObjectMirror) {
@@ -81,25 +76,6 @@
         });
     }
 
-    private  V inGlobal(final Callable callable) {
-        final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
-        final boolean globalChanged = (oldGlobal != global);
-        if (globalChanged) {
-            NashornScriptEngine.setNashornGlobal(global);
-        }
-        try {
-            return callable.call();
-        } catch (final RuntimeException e) {
-            throw e;
-        } catch (final Exception e) {
-            throw new AssertionError("Cannot happen", e);
-        } finally {
-            if (globalChanged) {
-                NashornScriptEngine.setNashornGlobal(oldGlobal);
-            }
-        }
-    }
-
     // JSObject methods
     @Override
     public Object call(final String functionName, final Object... args) {
@@ -212,6 +188,8 @@
         });
     }
 
+    // javax.script.Bindings methods
+
     @Override
     public void clear() {
         inGlobal(new Callable() {
@@ -308,9 +286,9 @@
     public void putAll(final Map map) {
         final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
         final boolean globalChanged = (oldGlobal != global);
-        final boolean strict = sobj.isStrictContext();
         inGlobal(new Callable() {
             @Override public Object call() {
+                final boolean strict = global.isStrictContext();
                 for (final Map.Entry entry : map.entrySet()) {
                     final Object value = entry.getValue();
                     final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
@@ -379,7 +357,7 @@
     public Object getProto() {
         return inGlobal(new Callable() {
             @Override public Object call() {
-                return wrap(getScriptObject().getProto(), global);
+                return wrap(sobj.getProto(), global);
             }
         });
     }
@@ -395,7 +373,7 @@
     public Object getOwnPropertyDescriptor(final String key) {
         return inGlobal(new Callable() {
             @Override public Object call() {
-                return wrap(getScriptObject().getOwnPropertyDescriptor(key), global);
+                return wrap(sobj.getOwnPropertyDescriptor(key), global);
             }
         });
     }
@@ -409,7 +387,7 @@
     public String[] getOwnKeys(final boolean all) {
         return inGlobal(new Callable() {
             @Override public String[] call() {
-                return getScriptObject().getOwnKeys(all);
+                return sobj.getOwnKeys(all);
             }
         });
     }
@@ -422,7 +400,7 @@
     public ScriptObjectMirror preventExtensions() {
         return inGlobal(new Callable() {
             @Override public ScriptObjectMirror call() {
-                getScriptObject().preventExtensions();
+                sobj.preventExtensions();
                 return ScriptObjectMirror.this;
             }
         });
@@ -435,7 +413,7 @@
     public boolean isExtensible() {
         return inGlobal(new Callable() {
             @Override public Boolean call() {
-                return getScriptObject().isExtensible();
+                return sobj.isExtensible();
             }
         });
     }
@@ -447,7 +425,7 @@
     public ScriptObjectMirror seal() {
         return inGlobal(new Callable() {
             @Override public ScriptObjectMirror call() {
-                getScriptObject().seal();
+                sobj.seal();
                 return ScriptObjectMirror.this;
             }
         });
@@ -460,7 +438,7 @@
     public boolean isSealed() {
         return inGlobal(new Callable() {
             @Override public Boolean call() {
-                return getScriptObject().isSealed();
+                return sobj.isSealed();
             }
         });
     }
@@ -472,7 +450,7 @@
     public ScriptObjectMirror freeze() {
         return inGlobal(new Callable() {
             @Override public ScriptObjectMirror call() {
-                getScriptObject().freeze();
+                sobj.freeze();
                 return ScriptObjectMirror.this;
             }
         });
@@ -485,7 +463,7 @@
     public boolean isFrozen() {
         return inGlobal(new Callable() {
             @Override public Boolean call() {
-                return getScriptObject().isFrozen();
+                return sobj.isFrozen();
             }
         });
     }
@@ -507,12 +485,39 @@
 
         return inGlobal(new Callable() {
             @Override public Boolean call() {
-                return getScriptObject().isInstance(instance.getScriptObject());
+                return sobj.isInstance(instance.sobj);
             }
         });
     }
 
     /**
+     * is this a function object?
+     *
+     * @return if this mirror wraps a ECMAScript function instance
+     */
+    public boolean isFunction() {
+        return sobj instanceof ScriptFunction;
+    }
+
+    /**
+     * is this a 'use strict' function object?
+     *
+     * @return true if this mirror represents a ECMAScript 'use strict' function
+     */
+    public boolean isStrictFunction() {
+        return isFunction() && ((ScriptFunction)sobj).isStrict();
+    }
+
+    /**
+     * is this an array object?
+     *
+     * @return if this mirror wraps a ECMAScript array object
+     */
+    public boolean isArray() {
+        return sobj.isArray();
+    }
+
+    /**
      * Utility to check if given object is ECMAScript undefined value
      *
      * @param obj object to check
@@ -523,35 +528,6 @@
     }
 
     /**
-     * is this a function object?
-     *
-     * @return if this mirror wraps a ECMAScript function instance
-     */
-    public boolean isFunction() {
-        return getScriptObject() instanceof ScriptFunction;
-    }
-
-    /**
-     * is this a 'use strict' function object?
-     *
-     * @return true if this mirror represents a ECMAScript 'use strict' function
-     */
-    public boolean isStrictFunction() {
-        return isFunction() && ((ScriptFunction)getScriptObject()).isStrict();
-    }
-
-    /**
-     * is this an array object?
-     *
-     * @return if this mirror wraps a ECMAScript array object
-     */
-    public boolean isArray() {
-        return getScriptObject().isArray();
-    }
-
-    // These are public only so that Context can access these.
-
-    /**
      * Make a script object mirror on given object if needed.
      *
      * @param obj object to be wrapped
@@ -621,6 +597,12 @@
     }
 
     // package-privates below this.
+
+    ScriptObjectMirror(final ScriptObject sobj, final ScriptObject global) {
+        this.sobj = sobj;
+        this.global = global;
+    }
+
     ScriptObject getScriptObject() {
         return sobj;
     }
@@ -628,4 +610,25 @@
     static Object translateUndefined(Object obj) {
         return (obj == ScriptRuntime.UNDEFINED)? null : obj;
     }
+
+    // internals only below this.
+    private  V inGlobal(final Callable callable) {
+        final ScriptObject oldGlobal = NashornScriptEngine.getNashornGlobal();
+        final boolean globalChanged = (oldGlobal != global);
+        if (globalChanged) {
+            NashornScriptEngine.setNashornGlobal(global);
+        }
+        try {
+            return callable.call();
+        } catch (final RuntimeException e) {
+            throw e;
+        } catch (final Exception e) {
+            throw new AssertionError("Cannot happen", e);
+        } finally {
+            if (globalChanged) {
+                NashornScriptEngine.setNashornGlobal(oldGlobal);
+            }
+        }
+    }
+
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/Attr.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java	Mon Jul 22 17:40:26 2013 -0700
@@ -61,6 +61,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -72,7 +73,6 @@
 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
-import jdk.nashorn.internal.ir.PropertyNode;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -94,7 +94,6 @@
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.Property;
 import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptObject;
 
 /**
  * This is the attribution pass of the code generator. Attr takes Lowered IR,
@@ -166,19 +165,19 @@
     }
 
     private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) {
-        initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE);
+        initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL);
         initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT);
 
         if (functionNode.isVarArg()) {
-            initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY);
+            initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL);
             if (functionNode.needsArguments()) {
-                initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
+                initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
                 addLocalDef(ARGUMENTS.symbolName());
             }
         }
 
         initParameters(functionNode, body);
-        initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.typeFor(ScriptObject.class));
+        initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED);
         initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL | IS_ALWAYS_DEFINED, Type.OBJECT);
     }
 
@@ -234,10 +233,25 @@
             @Override
             public boolean enterVarNode(final VarNode varNode) {
                 final String name = varNode.getName().getName();
-                //if this is used the var node symbol needs to be tagged as can be undefined
+                //if this is used before the var node, the var node symbol needs to be tagged as can be undefined
                 if (uses.contains(name)) {
                     canBeUndefined.add(name);
                 }
+
+                // all uses of the declared varnode inside the var node are potentially undefined
+                // however this is a bit conservative as e.g. var x = 17; var x = 1 + x; does work
+                if (!varNode.isFunctionDeclaration() && varNode.getInit() != null) {
+                    varNode.getInit().accept(new NodeVisitor(new LexicalContext()) {
+                       @Override
+                       public boolean enterIdentNode(final IdentNode identNode) {
+                           if (name.equals(identNode.getName())) {
+                              canBeUndefined.add(name);
+                           }
+                           return false;
+                       }
+                    });
+                }
+
                 return true;
             }
 
@@ -257,6 +271,7 @@
                     }
                     return varNode.setName((IdentNode)ident.setSymbol(lc, symbol));
                 }
+
                 return varNode;
             }
         });
@@ -326,10 +341,11 @@
         catchNestingLevel++;
 
         // define block-local exception variable
-        final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET | IS_ALWAYS_DEFINED);
+        final String exname = exception.getName();
+        final Symbol def = defineSymbol(block, exname, IS_VAR | IS_LET | IS_ALWAYS_DEFINED);
         newType(def, Type.OBJECT); //we can catch anything, not just ecma exceptions
 
-        addLocalDef(exception.getName());
+        addLocalDef(exname);
 
         return true;
     }
@@ -496,7 +512,6 @@
             assert nameSymbol != null;
 
             selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol));
-            selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol);
 
             newStatements.add(selfInit);
             newStatements.addAll(body.getStatements());
@@ -661,7 +676,7 @@
 
             if (scopeBlock != null) {
                 assert lc.contains(scopeBlock);
-                lc.setFlag(scopeBlock, Block.NEEDS_SCOPE);
+                lc.setBlockNeedsScope(scopeBlock);
             }
         }
     }
@@ -724,14 +739,9 @@
     }
 
     @Override
-    public Node leavePropertyNode(final PropertyNode propertyNode) {
-        // assign a pseudo symbol to property name, see NASHORN-710
-        return propertyNode.setSymbol(lc, new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
-    }
-
-    @Override
     public Node leaveReturnNode(final ReturnNode returnNode) {
-        final Node expr = returnNode.getExpression();
+        final Expression expr = returnNode.getExpression();
+        final Type returnType;
 
         if (expr != null) {
             //we can't do parameter specialization if we return something that hasn't been typed yet
@@ -740,10 +750,12 @@
                 symbol.setType(Type.OBJECT);
             }
 
-            final Type returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType());
-            returnTypes.push(returnType);
-            LOG.info("Returntype is now ", returnType);
+            returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType());
+        } else {
+            returnType = Type.OBJECT; //undefined
         }
+        LOG.info("Returntype is now ", returnType);
+        returnTypes.push(returnType);
 
         end(returnNode);
 
@@ -765,7 +777,7 @@
                     final LiteralNode lit = (LiteralNode)test;
                     if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
                         if (JSType.isRepresentableAsInt(lit.getNumber())) {
-                            newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
+                            newCaseNode = caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
                         }
                     }
                 } else {
@@ -774,6 +786,9 @@
                 }
 
                 type = Type.widest(type, newCaseNode.getTest().getType());
+                if (type.isBoolean()) {
+                    type = Type.OBJECT; //booleans and integers aren't assignment compatible
+                }
             }
 
             newCases.add(newCaseNode);
@@ -825,19 +840,18 @@
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
-        VarNode newVarNode = varNode;
+        final Expression init  = varNode.getInit();
+        final IdentNode  ident = varNode.getName();
+        final String     name  = ident.getName();
 
-        final Node      init  = newVarNode.getInit();
-        final IdentNode ident = newVarNode.getName();
-        final String    name  = ident.getName();
-
-        final Symbol  symbol = findSymbol(lc.getCurrentBlock(), ident.getName());
+        final Symbol  symbol = findSymbol(lc.getCurrentBlock(), name);
+        assert ident.getSymbol() == symbol;
 
         if (init == null) {
             // var x; with no init will be treated like a use of x by
             // leaveIdentNode unless we remove the name from the localdef list.
             removeLocalDef(name);
-            return end(newVarNode.setSymbol(lc, symbol));
+            return end(varNode);
         }
 
         addLocalDef(name);
@@ -846,8 +860,7 @@
 
         final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol);
 
-        newVarNode = newVarNode.setName(newIdent);
-        newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol);
+        final VarNode newVarNode = varNode.setName(newIdent);
 
         final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56
         if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
@@ -857,7 +870,7 @@
             newType(symbol, Type.OBJECT);
         }
 
-        assert newVarNode.hasType() : newVarNode + " has no type";
+        assert newVarNode.getName().hasType() : newVarNode + " has no type";
 
         return end(newVarNode);
     }
@@ -885,11 +898,11 @@
     public Node leaveDELETE(final UnaryNode unaryNode) {
         final FunctionNode   currentFunctionNode = lc.getCurrentFunction();
         final boolean        strictMode          = currentFunctionNode.isStrict();
-        final Node           rhs                 = unaryNode.rhs();
-        final Node           strictFlagNode      = LiteralNode.newInstance(unaryNode, strictMode).accept(this);
+        final Expression     rhs                 = unaryNode.rhs();
+        final Expression     strictFlagNode      = (Expression)LiteralNode.newInstance(unaryNode, strictMode).accept(this);
 
         Request request = Request.DELETE;
-        final List args = new ArrayList<>();
+        final List args = new ArrayList<>();
 
         if (rhs instanceof IdentNode) {
             // If this is a declared variable or a function parameter, delete always fails (except for globals).
@@ -900,7 +913,7 @@
             if (failDelete && rhs.getSymbol().isThis()) {
                 return LiteralNode.newInstance(unaryNode, true).accept(this);
             }
-            final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this);
+            final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
 
             if (!failDelete) {
                 args.add(compilerConstant(SCOPE));
@@ -912,16 +925,17 @@
                 request = Request.FAIL_DELETE;
             }
         } else if (rhs instanceof AccessNode) {
-            final Node      base     = ((AccessNode)rhs).getBase();
-            final IdentNode property = ((AccessNode)rhs).getProperty();
+            final Expression base     = ((AccessNode)rhs).getBase();
+            final IdentNode  property = ((AccessNode)rhs).getProperty();
 
             args.add(base);
-            args.add(LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
+            args.add((Expression)LiteralNode.newInstance(unaryNode, property.getName()).accept(this));
             args.add(strictFlagNode);
 
         } else if (rhs instanceof IndexNode) {
-            final Node base  = ((IndexNode)rhs).getBase();
-            final Node index = ((IndexNode)rhs).getIndex();
+            final IndexNode indexNode = (IndexNode)rhs;
+            final Expression base  = indexNode.getBase();
+            final Expression index = indexNode.getIndex();
 
             args.add(base);
             args.add(index);
@@ -976,15 +990,15 @@
 
     @Override
     public Node leaveTYPEOF(final UnaryNode unaryNode) {
-        final Node rhs = unaryNode.rhs();
+        final Expression rhs = unaryNode.rhs();
 
-        List args = new ArrayList<>();
+        List args = new ArrayList<>();
         if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) {
             args.add(compilerConstant(SCOPE));
-            args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
+            args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
         } else {
             args.add(rhs);
-            args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
+            args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
         }
 
         RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
@@ -1009,10 +1023,7 @@
 
     @Override
     public Node leaveVOID(final UnaryNode unaryNode) {
-        final RuntimeNode runtimeNode = (RuntimeNode)new RuntimeNode(unaryNode, Request.VOID).accept(this);
-        assert runtimeNode.getSymbol().getSymbolType().isObject();
-        end(unaryNode);
-        return runtimeNode;
+        return end(ensureSymbol(Type.OBJECT, unaryNode));
     }
 
     /**
@@ -1021,8 +1032,8 @@
      */
     @Override
     public Node leaveADD(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         ensureTypeNotUnknown(lhs);
         ensureTypeNotUnknown(rhs);
@@ -1077,8 +1088,8 @@
     private Node leaveAssignmentNode(final BinaryNode binaryNode) {
         BinaryNode newBinaryNode = binaryNode;
 
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
         final Type type;
 
         if (rhs.getType().isNumeric()) {
@@ -1114,8 +1125,8 @@
 
     @Override
     public Node leaveASSIGN_ADD(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         final Type widest = Type.widest(lhs.getType(), rhs.getType());
         //Type.NUMBER if we can't prove that the add doesn't overflow. todo
@@ -1394,19 +1405,26 @@
 
     @Override
     public Node leaveTernaryNode(final TernaryNode ternaryNode) {
-        final Node lhs  = ternaryNode.rhs();
-        final Node rhs  = ternaryNode.third();
+        final Expression trueExpr  = ternaryNode.getTrueExpression();
+        final Expression falseExpr = ternaryNode.getFalseExpression();
+
+        ensureTypeNotUnknown(trueExpr);
+        ensureTypeNotUnknown(falseExpr);
 
-        ensureTypeNotUnknown(lhs);
-        ensureTypeNotUnknown(rhs);
+        final Type type = Type.widest(trueExpr.getType(), falseExpr.getType());
+        return end(ensureSymbol(type, ternaryNode));
+    }
 
-        final Type type = Type.widest(lhs.getType(), rhs.getType());
-        return end(ensureSymbol(type, ternaryNode));
+    private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags) {
+        final Class type = cc.type();
+        // Must not call this method for constants with no explicit types; use the one with (..., Type) signature instead.
+        assert type != null;
+        initCompileConstant(cc, block, flags, Type.typeFor(type));
     }
 
     private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) {
         final Symbol symbol = defineSymbol(block, cc.symbolName(), flags);
-        newType(symbol, type);
+        symbol.setTypeOverride(type);
         symbol.setNeedsSlot(true);
     }
 
@@ -1511,7 +1529,7 @@
         }
     }
 
-    private static void ensureTypeNotUnknown(final Node node) {
+    private static void ensureTypeNotUnknown(final Expression node) {
 
         final Symbol symbol = node.getSymbol();
 
@@ -1568,13 +1586,13 @@
      *
      * @param assignmentDest the destination node of the assignment, e.g. lhs for binary nodes
      */
-    private Node ensureAssignmentSlots(final Node assignmentDest) {
+    private Expression ensureAssignmentSlots(final Expression assignmentDest) {
         final LexicalContext attrLexicalContext = lc;
-        return assignmentDest.accept(new NodeVisitor(new LexicalContext()) {
+        return (Expression)assignmentDest.accept(new NodeVisitor(new LexicalContext()) {
             @Override
             public Node leaveIndexNode(final IndexNode indexNode) {
                 assert indexNode.getSymbol().isTemp();
-                final Node index = indexNode.getIndex();
+                final Expression index = indexNode.getIndex();
                 //only temps can be set as needing slots. the others will self resolve
                 //it is illegal to take a scope var and force it to be a slot, that breaks
                 Symbol indexSymbol = index.getSymbol();
@@ -1616,7 +1634,7 @@
             changed.clear();
             final FunctionNode newFunctionNode = (FunctionNode)currentFunctionNode.accept(new NodeVisitor(new LexicalContext()) {
 
-                private Node widen(final Node node, final Type to) {
+                private Expression widen(final Expression node, final Type to) {
                     if (node instanceof LiteralNode) {
                         return node;
                     }
@@ -1628,7 +1646,7 @@
                             symbol = temporarySymbols.getTypedTemporarySymbol(to);
                         }
                         newType(symbol, to);
-                        final Node newNode = node.setSymbol(lc, symbol);
+                        final Expression newNode = node.setSymbol(lc, symbol);
                         changed.add(newNode);
                         return newNode;
                     }
@@ -1683,7 +1701,7 @@
 
     private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode, final Type destType) {
         //e.g. for -=, Number, no wider, destType (binaryNode.getWidestOperationType())  is the coerce type
-        final Node lhs = binaryNode.lhs();
+        final Expression lhs = binaryNode.lhs();
 
         newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType
 //        ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine
@@ -1691,9 +1709,9 @@
         return end(ensureSymbol(destType, ensureAssignmentSlots(binaryNode)));
     }
 
-    private Node ensureSymbol(final Type type, final Node node) {
+    private Expression ensureSymbol(final Type type, final Expression expr) {
         LOG.info("New TEMPORARY added to ", lc.getCurrentFunction().getName(), " type=", type);
-        return temporarySymbols.ensureSymbol(lc, type, node);
+        return temporarySymbols.ensureSymbol(lc, type, expr);
     }
 
     private Symbol newInternal(final String name, final Type type) {
@@ -1815,11 +1833,11 @@
         return true;
     }
 
-    private Node end(final Node node) {
+    private  T end(final T node) {
         return end(node, true);
     }
 
-    private Node end(final Node node, final boolean printNode) {
+    private  T end(final T node, final boolean printNode) {
         if(node instanceof Statement) {
             // If we're done with a statement, all temporaries can be reused.
             temporarySymbols.reuse();
@@ -1834,10 +1852,13 @@
                 append(" in '").
                 append(lc.getCurrentFunction().getName());
 
-            if (node.getSymbol() == null) {
-                sb.append(" ");
-            } else {
-                sb.append(" ');
+            if(node instanceof Expression) {
+                final Symbol symbol = ((Expression)node).getSymbol();
+                if (symbol == null) {
+                    sb.append(" ");
+                } else {
+                    sb.append(" ');
+                }
             }
 
             LOG.unindent();
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/BranchOptimizer.java	Mon Jul 22 17:40:26 2013 -0700
@@ -34,7 +34,7 @@
 
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.BinaryNode;
-import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.TernaryNode;
 import jdk.nashorn.internal.ir.UnaryNode;
 
@@ -52,16 +52,16 @@
         this.method  = method;
     }
 
-    void execute(final Node node, final Label label, final boolean state) {
+    void execute(final Expression node, final Label label, final boolean state) {
         branchOptimizer(node, label, state);
     }
 
-    private void load(final Node node) {
+    private void load(final Expression node) {
         codegen.load(node);
     }
 
     private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) {
-        final Node rhs = unaryNode.rhs();
+        final Expression rhs = unaryNode.rhs();
 
         switch (unaryNode.tokenType()) {
         case NOT:
@@ -88,8 +88,8 @@
     }
 
     private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         switch (binaryNode.tokenType()) {
         case AND:
@@ -173,7 +173,7 @@
         }
     }
 
-    private void branchOptimizer(final Node node, final Label label, final boolean state) {
+    private void branchOptimizer(final Expression node, final Label label, final boolean state) {
         if (!(node instanceof TernaryNode)) {
 
             if (node instanceof BinaryNode) {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -55,10 +55,12 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.TreeMap;
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -69,6 +71,7 @@
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
 import jdk.nashorn.internal.ir.BreakNode;
 import jdk.nashorn.internal.ir.BreakableNode;
 import jdk.nashorn.internal.ir.CallNode;
@@ -76,7 +79,8 @@
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -109,6 +113,8 @@
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.objects.Global;
+import jdk.nashorn.internal.objects.ScriptFunctionImpl;
 import jdk.nashorn.internal.parser.Lexer.RegexToken;
 import jdk.nashorn.internal.parser.TokenType;
 import jdk.nashorn.internal.runtime.Context;
@@ -148,11 +154,9 @@
  */
 final class CodeGenerator extends NodeOperatorVisitor {
 
-    /** Name of the Global object, cannot be referred to as .class, @see CodeGenerator */
-    private static final String GLOBAL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "Global";
-
-    /** Name of the ScriptFunctionImpl, cannot be referred to as .class @see FunctionObjectCreator */
-    private static final String SCRIPTFUNCTION_IMPL_OBJECT = Compiler.OBJECTS_PACKAGE + '/' + "ScriptFunctionImpl";
+    private static final String GLOBAL_OBJECT = Type.getInternalName(Global.class);
+
+    private static final String SCRIPTFUNCTION_IMPL_OBJECT = Type.getInternalName(ScriptFunctionImpl.class);
 
     /** Constant data & installation. The only reason the compiler keeps this is because it is assigned
      *  by reflection in class installation */
@@ -179,6 +183,10 @@
 
     private static final DebugLogger LOG   = new DebugLogger("codegen", "nashorn.codegen.debug");
 
+    /** From what size should we use spill instead of fields for JavaScript objects? */
+    private static final int OBJECT_SPILL_THRESHOLD = 300;
+
+    private final Set emittedMethods = new HashSet<>();
 
     /**
      * Constructor.
@@ -348,11 +356,11 @@
      *
      * @return the method emitter used
      */
-    MethodEmitter load(final Node node) {
+    MethodEmitter load(final Expression node) {
         return load(node, false);
     }
 
-    private MethodEmitter load(final Node node, final boolean baseAlreadyOnStack) {
+    private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) {
         final Symbol symbol = node.getSymbol();
 
         // If we lack symbols, we just generate what we see.
@@ -486,6 +494,9 @@
 
     @Override
     public boolean enterBlock(final Block block) {
+        if(lc.isFunctionBody() && emittedMethods.contains(lc.getCurrentFunction().getName())) {
+            return false;
+        }
         method.label(block.getEntryLabel());
         initLocals(block);
 
@@ -537,11 +548,11 @@
         return false;
     }
 
-    private int loadArgs(final List args) {
+    private int loadArgs(final List args) {
         return loadArgs(args, null, false, args.size());
     }
 
-    private int loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) {
+    private int loadArgs(final List args, final String signature, final boolean isVarArg, final int argCount) {
         // arg have already been converted to objects here.
         if (isVarArg || argCount > LinkerCallSite.ARGLIMIT) {
             loadArgsArray(args);
@@ -551,7 +562,7 @@
         // pad with undefined if size is too short. argCount is the real number of args
         int n = 0;
         final Type[] params = signature == null ? null : Type.getMethodArguments(signature);
-        for (final Node arg : args) {
+        for (final Expression arg : args) {
             assert arg != null;
             load(arg);
             if (n >= argCount) {
@@ -572,12 +583,13 @@
 
     @Override
     public boolean enterCallNode(final CallNode callNode) {
-        lineNumber(callNode);
-
-        final List   args            = callNode.getArgs();
-        final Node         function        = callNode.getFunction();
-        final Block        currentBlock    = lc.getCurrentBlock();
+        lineNumber(callNode.getLineNumber());
+
+        final List args = callNode.getArgs();
+        final Expression function = callNode.getFunction();
+        final Block currentBlock = lc.getCurrentBlock();
         final CodeGeneratorLexicalContext codegenLexicalContext = lc;
+        final Type callNodeType = callNode.getType();
 
         function.accept(new NodeVisitor(new LexicalContext()) {
 
@@ -593,7 +605,7 @@
                 }
                 loadArgs(args);
                 final Type[] paramTypes = method.getTypesFromStack(args.size());
-                final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNode.getType(), paramTypes, scopeCallFlags);
+                final SharedScopeCall scopeCall = codegenLexicalContext.getScopeCall(unit, symbol, identNode.getType(), callNodeType, paramTypes, scopeCallFlags);
                 return scopeCall.generateInvoke(method);
             }
 
@@ -602,7 +614,7 @@
                 method.convert(Type.OBJECT); // foo() makes no sense if foo == 3
                 // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly.
                 method.loadNull(); //the 'this'
-                method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags);
+                method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
             }
 
             private void evalCall(final IdentNode node, final int flags) {
@@ -634,14 +646,14 @@
 
                 // direct call to Global.directEval
                 globalDirectEval();
-                method.convert(callNode.getType());
+                method.convert(callNodeType);
                 method._goto(eval_done);
 
                 method.label(not_eval);
                 // This is some scope 'eval' or global eval replaced by user
                 // but not the built-in ECMAScript 'eval' function call
                 method.loadNull();
-                method.dynamicCall(callNode.getType(), 2 + loadArgs(args), flags);
+                method.dynamicCall(callNodeType, 2 + loadArgs(args), flags);
 
                 method.label(eval_done);
             }
@@ -666,7 +678,7 @@
                     } else {
                         sharedScopeCall(node, flags);
                     }
-                    assert method.peekType().equals(callNode.getType()) : method.peekType() + "!=" + callNode.getType();
+                    assert method.peekType().equals(callNodeType) : method.peekType() + "!=" + callNode.getType();
                 } else {
                     enterDefault(node);
                 }
@@ -681,8 +693,8 @@
                 method.dup();
                 method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true);
                 method.swap();
-                method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
-                assert method.peekType().equals(callNode.getType());
+                method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
+                assert method.peekType().equals(callNodeType);
 
                 return false;
             }
@@ -707,6 +719,7 @@
                 assert callee.getCompileUnit() != null : "no compile unit for " + callee.getName() + " " + Debug.id(callee) + " " + callNode;
                 method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
                 assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
+                method.convert(callNodeType);
                 return false;
             }
 
@@ -722,7 +735,7 @@
                 }
                 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true);
                 method.swap();
-                method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags());
+                method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags());
                 assert method.peekType().equals(callNode.getType());
 
                 return false;
@@ -734,7 +747,7 @@
                 load(function);
                 method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions
                 method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE
-                method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
+                method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE);
                 assert method.peekType().equals(callNode.getType());
 
                 return false;
@@ -767,11 +780,19 @@
     }
 
     @Override
-    public boolean enterExecuteNode(final ExecuteNode executeNode) {
-        lineNumber(executeNode);
-
-        final Node expression = executeNode.getExpression();
-        expression.accept(this);
+    public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+        lineNumber(expressionStatement);
+
+        expressionStatement.getExpression().accept(this);
+
+        return false;
+    }
+
+    @Override
+    public boolean enterBlockStatement(final BlockStatement blockStatement) {
+        lineNumber(blockStatement);
+
+        blockStatement.getBlock().accept(this);
 
         return false;
     }
@@ -790,10 +811,10 @@
     }
 
     private void enterFor(final ForNode forNode) {
-        final Node  init   = forNode.getInit();
-        final Node  test   = forNode.getTest();
-        final Block body   = forNode.getBody();
-        final Node  modify = forNode.getModify();
+        final Expression init   = forNode.getInit();
+        final Expression test   = forNode.getTest();
+        final Block      body   = forNode.getBody();
+        final Expression modify = forNode.getModify();
 
         if (init != null) {
             init.accept(this);
@@ -823,19 +844,13 @@
 
     private void enterForIn(final ForNode forNode) {
         final Block body   = forNode.getBody();
-        final Node  modify = forNode.getModify();
+        final Expression  modify = forNode.getModify();
 
         final Symbol iter      = forNode.getIterator();
         final Label  loopLabel = new Label("loop");
 
-        Node init = forNode.getInit();
-
-        // We have to evaluate the optional initializer expression
-        // of the iterator variable of the for-in statement.
-        if (init instanceof VarNode) {
-            init.accept(this);
-            init = ((VarNode)init).getName();
-        }
+        final Expression init = forNode.getInit();
+        assert init instanceof IdentNode;
 
         load(modify);
         assert modify.getType().isObject();
@@ -844,7 +859,7 @@
         method._goto(forNode.getContinueLabel());
         method.label(loopLabel);
 
-        new Store(init) {
+        new Store(init) {
             @Override
             protected void storeNonDiscard() {
                 return;
@@ -877,9 +892,15 @@
 
         final FunctionNode function = lc.getCurrentFunction();
         if (isFunctionBody) {
-            /* Fix the predefined slots so they have numbers >= 0, like varargs. */
-            if (function.needsParentScope()) {
-                initParentScope();
+            if(method.hasScope()) {
+                if (function.needsParentScope()) {
+                    method.loadCompilerConstant(CALLEE);
+                    method.invoke(ScriptFunction.GET_SCOPE);
+                } else {
+                    assert function.hasScopeBlock();
+                    method.loadNull();
+                }
+                method.storeCompilerConstant(SCOPE);
             }
             if (function.needsArguments()) {
                 initArguments(function);
@@ -940,22 +961,12 @@
              * Create a new object based on the symbols and values, generate
              * bootstrap code for object
              */
-            final FieldObjectCreator foc = new FieldObjectCreator(this, nameList, newSymbols, values, true, hasArguments) {
+            new FieldObjectCreator(this, nameList, newSymbols, values, true, hasArguments) {
                 @Override
                 protected void loadValue(final Symbol value) {
                     method.load(value);
                 }
-
-                @Override
-                protected void loadScope(MethodEmitter m) {
-                    if (function.needsParentScope()) {
-                        m.loadCompilerConstant(SCOPE);
-                    } else {
-                        m.loadNull();
-                    }
-                }
-            };
-            foc.makeObject(method);
+            }.makeObject(method);
 
             // runScript(): merge scope into global
             if (isFunctionBody && function.isProgram()) {
@@ -995,12 +1006,6 @@
         method.storeCompilerConstant(ARGUMENTS);
     }
 
-    private void initParentScope() {
-        method.loadCompilerConstant(CALLEE);
-        method.invoke(ScriptFunction.GET_SCOPE);
-        method.storeCompilerConstant(SCOPE);
-    }
-
     @Override
     public boolean enterFunctionNode(final FunctionNode functionNode) {
         if (functionNode.isLazy()) {
@@ -1009,17 +1014,28 @@
             return false;
         }
 
-        LOG.info("=== BEGIN ", functionNode.getName());
-
-        assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode);
-        unit = lc.pushCompileUnit(functionNode.getCompileUnit());
-        assert lc.hasCompileUnits();
-
-        method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
-        // new method - reset last line number
-        lastLineNumber = -1;
-        // Mark end for variable tables.
-        method.begin();
+        final String fnName = functionNode.getName();
+        // NOTE: we only emit the method for a function with the given name once. We can have multiple functions with
+        // the same name as a result of inlining finally blocks. However, in the future -- with type specialization,
+        // notably -- we might need to check for both name *and* signature. Of course, even that might not be
+        // sufficient; the function might have a code dependency on the type of the variables in its enclosing scopes,
+        // and the type of such a variable can be different in catch and finally blocks. So, in the future we will have
+        // to decide to either generate a unique method for each inlined copy of the function, maybe figure out its
+        // exact type closure and deduplicate based on that, or just decide that functions in finally blocks aren't
+        // worth it, and generate one method with most generic type closure.
+        if(!emittedMethods.contains(fnName)) {
+            LOG.info("=== BEGIN ", fnName);
+
+            assert functionNode.getCompileUnit() != null : "no compile unit for " + fnName + " " + Debug.id(functionNode);
+            unit = lc.pushCompileUnit(functionNode.getCompileUnit());
+            assert lc.hasCompileUnits();
+
+            method = lc.pushMethodEmitter(unit.getClassEmitter().method(functionNode));
+            // new method - reset last line number
+            lastLineNumber = -1;
+            // Mark end for variable tables.
+            method.begin();
+        }
 
         return true;
     }
@@ -1027,13 +1043,14 @@
     @Override
     public Node leaveFunctionNode(final FunctionNode functionNode) {
         try {
-            method.end(); // wrap up this method
-            unit   = lc.popCompileUnit(functionNode.getCompileUnit());
-            method = lc.popMethodEmitter(method);
-            LOG.info("=== END ", functionNode.getName());
+            if(emittedMethods.add(functionNode.getName())) {
+                method.end(); // wrap up this method
+                unit   = lc.popCompileUnit(functionNode.getCompileUnit());
+                method = lc.popMethodEmitter(method);
+                LOG.info("=== END ", functionNode.getName());
+            }
 
             final FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.EMITTED);
-
             newFunctionObject(newFunctionNode, functionNode);
             return newFunctionNode;
         } catch (final Throwable t) {
@@ -1053,7 +1070,7 @@
     public boolean enterIfNode(final IfNode ifNode) {
         lineNumber(ifNode);
 
-        final Node  test = ifNode.getTest();
+        final Expression test = ifNode.getTest();
         final Block pass = ifNode.getPass();
         final Block fail = ifNode.getFail();
 
@@ -1093,7 +1110,10 @@
     }
 
     private void lineNumber(final Statement statement) {
-        final int lineNumber = statement.getLineNumber();
+        lineNumber(statement.getLineNumber());
+    }
+
+    private void lineNumber(int lineNumber) {
         if (lineNumber != lastLineNumber) {
             method.lineNumber(lineNumber);
         }
@@ -1112,7 +1132,7 @@
     private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
         assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
 
-        final Node[]          nodes    = arrayLiteralNode.getValue();
+        final Expression[]    nodes    = arrayLiteralNode.getValue();
         final Object          presets  = arrayLiteralNode.getPresets();
         final int[]           postsets = arrayLiteralNode.getPostsets();
         final Class        type     = arrayType.getTypeClass();
@@ -1172,11 +1192,11 @@
         return method;
     }
 
-    private void storeElement(final Node[] nodes, final Type elementType, final int index) {
+    private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
         method.dup();
         method.load(index);
 
-        final Node element = nodes[index];
+        final Expression element = nodes[index];
 
         if (element == null) {
             method.loadEmpty(elementType);
@@ -1188,7 +1208,7 @@
         method.arraystore();
     }
 
-    private MethodEmitter loadArgsArray(final List args) {
+    private MethodEmitter loadArgsArray(final List args) {
         final Object[] array = new Object[args.size()];
         loadConstant(array);
 
@@ -1318,9 +1338,8 @@
         return method;
     }
 
-    @SuppressWarnings("rawtypes")
     @Override
-    public boolean enterLiteralNode(final LiteralNode literalNode) {
+    public boolean enterLiteralNode(final LiteralNode literalNode) {
         assert literalNode.getSymbol() != null : literalNode + " has no symbol";
         load(literalNode).store(literalNode.getSymbol());
         return false;
@@ -1330,16 +1349,16 @@
     public boolean enterObjectNode(final ObjectNode objectNode) {
         final List elements = objectNode.getElements();
 
-        final List keys    = new ArrayList<>();
-        final List symbols = new ArrayList<>();
-        final List   values  = new ArrayList<>();
+        final List     keys    = new ArrayList<>();
+        final List     symbols = new ArrayList<>();
+        final List values  = new ArrayList<>();
 
         boolean hasGettersSetters = false;
 
         for (PropertyNode propertyNode: elements) {
-            final Node         value        = propertyNode.getValue();
+            final Expression   value        = propertyNode.getValue();
             final String       key          = propertyNode.getKeyName();
-            final Symbol       symbol       = value == null ? null : propertyNode.getSymbol();
+            final Symbol       symbol       = value == null ? null : propertyNode.getKey().getSymbol();
 
             if (value == null) {
                 hasGettersSetters = true;
@@ -1350,73 +1369,71 @@
             values.add(value);
         }
 
-        new FieldObjectCreator(this, keys, symbols, values) {
-            @Override
-            protected void loadValue(final Node node) {
-                load(node);
-            }
-
-            /**
-             * Ensure that the properties start out as object types so that
-             * we can do putfield initializations instead of dynamicSetIndex
-             * which would be the case to determine initial property type
-             * otherwise.
-             *
-             * Use case, it's very expensive to do a million var x = {a:obj, b:obj}
-             * just to have to invalidate them immediately on initialization
-             *
-             * see NASHORN-594
-             */
-            @Override
-            protected MapCreator newMapCreator(final Class fieldObjectClass) {
-                return new MapCreator(fieldObjectClass, keys, symbols) {
-                    @Override
-                    protected int getPropertyFlags(final Symbol symbol, final boolean isVarArg) {
-                        return super.getPropertyFlags(symbol, isVarArg) | Property.IS_ALWAYS_OBJECT;
-                    }
-                };
-            }
-
-        }.makeObject(method);
+        if (elements.size() > OBJECT_SPILL_THRESHOLD) {
+            new SpillObjectCreator(this, keys, symbols, values).makeObject(method);
+        } else {
+            new FieldObjectCreator(this, keys, symbols, values) {
+                @Override
+                protected void loadValue(final Expression node) {
+                    load(node);
+                }
+
+                /**
+                 * Ensure that the properties start out as object types so that
+                 * we can do putfield initializations instead of dynamicSetIndex
+                 * which would be the case to determine initial property type
+                 * otherwise.
+                 *
+                 * Use case, it's very expensive to do a million var x = {a:obj, b:obj}
+                 * just to have to invalidate them immediately on initialization
+                 *
+                 * see NASHORN-594
+                 */
+                @Override
+                protected MapCreator newMapCreator(final Class fieldObjectClass) {
+                    return new MapCreator(fieldObjectClass, keys, symbols) {
+                        @Override
+                        protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
+                            return super.getPropertyFlags(symbol, hasArguments) | Property.IS_ALWAYS_OBJECT;
+                        }
+                    };
+                }
+
+            }.makeObject(method);
+        }
 
         method.dup();
         globalObjectPrototype();
         method.invoke(ScriptObject.SET_PROTO);
 
-        if (!hasGettersSetters) {
-            method.store(objectNode.getSymbol());
-            return false;
-        }
-
-        for (final Node element : elements) {
-            final PropertyNode propertyNode = (PropertyNode)element;
-            final Object       key          = propertyNode.getKey();
-            final FunctionNode getter       = propertyNode.getGetter();
-            final FunctionNode setter       = propertyNode.getSetter();
-
-            if (getter == null && setter == null) {
-                continue;
+        if (hasGettersSetters) {
+            for (final PropertyNode propertyNode : elements) {
+                final FunctionNode getter       = propertyNode.getGetter();
+                final FunctionNode setter       = propertyNode.getSetter();
+
+                if (getter == null && setter == null) {
+                    continue;
+                }
+
+                method.dup().loadKey(propertyNode.getKey());
+
+                if (getter == null) {
+                    method.loadNull();
+                } else {
+                    getter.accept(this);
+                }
+
+                if (setter == null) {
+                    method.loadNull();
+                } else {
+                    setter.accept(this);
+                }
+
+                method.invoke(ScriptObject.SET_USER_ACCESSORS);
             }
-
-            method.dup().loadKey(key);
-
-            if (getter == null) {
-                method.loadNull();
-            } else {
-                getter.accept(this);
-            }
-
-            if (setter == null) {
-                method.loadNull();
-            } else {
-                setter.accept(this);
-            }
-
-            method.invoke(ScriptObject.SET_USER_ACCESSORS);
         }
 
         method.store(objectNode.getSymbol());
-
         return false;
     }
 
@@ -1428,7 +1445,7 @@
 
         final Type returnType = lc.getCurrentFunction().getReturnType();
 
-        final Node expression = returnNode.getExpression();
+        final Expression expression = returnNode.getExpression();
         if (expression != null) {
             load(expression);
         } else {
@@ -1444,7 +1461,7 @@
         return node instanceof LiteralNode && ((LiteralNode) node).isNull();
     }
 
-    private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) {
+    private boolean nullCheck(final RuntimeNode runtimeNode, final List args, final String signature) {
         final Request request = runtimeNode.getRequest();
 
         if (!Request.isEQ(request) && !Request.isNE(request)) {
@@ -1453,11 +1470,11 @@
 
         assert args.size() == 2 : "EQ or NE or TYPEOF need two args";
 
-        Node lhs = args.get(0);
-        Node rhs = args.get(1);
+        Expression lhs = args.get(0);
+        Expression rhs = args.get(1);
 
         if (isNullLiteral(lhs)) {
-            final Node tmp = lhs;
+            final Expression tmp = lhs;
             lhs = rhs;
             rhs = tmp;
         }
@@ -1511,7 +1528,7 @@
         return false;
     }
 
-    private boolean specializationCheck(final RuntimeNode.Request request, final Node node, final List args) {
+    private boolean specializationCheck(final RuntimeNode.Request request, final Expression node, final List args) {
         if (!request.canSpecialize()) {
             return false;
         }
@@ -1564,10 +1581,11 @@
          *
          * TODO - remove this - Access Specializer will always know after Attr/Lower
          */
+        final List args = runtimeNode.getArgs();
         if (runtimeNode.isPrimitive() && !runtimeNode.isFinal() && isReducible(runtimeNode.getRequest())) {
-            final Node lhs = runtimeNode.getArgs().get(0);
-            assert runtimeNode.getArgs().size() > 1 : runtimeNode + " must have two args";
-            final Node rhs = runtimeNode.getArgs().get(1);
+            final Expression lhs = args.get(0);
+            assert args.size() > 1 : runtimeNode + " must have two args";
+            final Expression rhs = args.get(1);
 
             final Type   type   = runtimeNode.getType();
             final Symbol symbol = runtimeNode.getSymbol();
@@ -1604,9 +1622,6 @@
             }
         }
 
-        // Get the request arguments.
-        final List args = runtimeNode.getArgs();
-
         if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) {
             return false;
         }
@@ -1615,7 +1630,7 @@
             return false;
         }
 
-        for (final Node arg : runtimeNode.getArgs()) {
+        for (final Expression arg : args) {
             load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower
         }
 
@@ -1626,7 +1641,7 @@
                 false,
                 false,
                 runtimeNode.getType(),
-                runtimeNode.getArgs().size()).toString());
+                args.size()).toString());
         method.convert(runtimeNode.getType());
         method.store(runtimeNode.getSymbol());
 
@@ -1635,8 +1650,6 @@
 
     @Override
     public boolean enterSplitNode(final SplitNode splitNode) {
-        lineNumber(splitNode);
-
         final CompileUnit splitCompileUnit = splitNode.getCompileUnit();
 
         final FunctionNode fn   = lc.getCurrentFunction();
@@ -1781,7 +1794,7 @@
     public boolean enterSwitchNode(final SwitchNode switchNode) {
         lineNumber(switchNode);
 
-        final Node           expression  = switchNode.getExpression();
+        final Expression     expression  = switchNode.getExpression();
         final Symbol         tag         = switchNode.getTag();
         final boolean        allInteger  = tag.getSymbolType().isInteger();
         final List cases       = switchNode.getCases();
@@ -1847,7 +1860,7 @@
             // If expression not int see if we can convert, if not use deflt to trigger default.
             if (!type.isInteger()) {
                 method.load(deflt);
-                final Class exprClass = type.getTypeClass();
+                final Class exprClass = type.getTypeClass();
                 method.invoke(staticCallNoLookup(ScriptRuntime.class, "switchTagAsInt", int.class, exprClass.isPrimitive()? exprClass : Object.class, int.class));
             }
 
@@ -1878,11 +1891,13 @@
                 method.store(tag);
                 method.conditionalJump(Condition.NE, true, defaultLabel);
             } else {
+                assert tag.getSymbolType().isObject();
+                method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object
                 method.store(tag);
             }
 
             for (final CaseNode caseNode : cases) {
-                final Node test = caseNode.getTest();
+                final Expression test = caseNode.getTest();
 
                 if (test != null) {
                     method.load(tag);
@@ -1922,10 +1937,10 @@
 
         final Source source     = lc.getCurrentFunction().getSource();
 
-        final Node   expression = throwNode.getExpression();
-        final int    position   = throwNode.position();
-        final int    line       = source.getLine(position);
-        final int    column     = source.getColumn(position);
+        final Expression expression = throwNode.getExpression();
+        final int        position   = throwNode.position();
+        final int        line       = source.getLine(position);
+        final int        column     = source.getColumn(position);
 
         load(expression);
         assert expression.getType().isObject();
@@ -1974,10 +1989,10 @@
             lc.push(catchBlock);
             enterBlock(catchBlock);
 
-            final CatchNode catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
-            final IdentNode exception          = catchNode.getException();
-            final Node      exceptionCondition = catchNode.getExceptionCondition();
-            final Block     catchBody          = catchNode.getBody();
+            final CatchNode  catchNode          = (CatchNode)catchBlocks.get(i).getStatements().get(0);
+            final IdentNode  exception          = catchNode.getException();
+            final Expression exceptionCondition = catchNode.getExceptionCondition();
+            final Block      catchBody          = catchNode.getBody();
 
             new Store(exception) {
                 @Override
@@ -2045,7 +2060,7 @@
     @Override
     public boolean enterVarNode(final VarNode varNode) {
 
-        final Node init = varNode.getInit();
+        final Expression init = varNode.getInit();
 
         if (init == null) {
             return false;
@@ -2053,8 +2068,8 @@
 
         lineNumber(varNode);
 
-        final Symbol varSymbol = varNode.getSymbol();
-        assert varSymbol != null : "variable node " + varNode + " requires a symbol";
+        final Symbol varSymbol = varNode.getName().getSymbol();
+        assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol";
 
         assert method != null;
 
@@ -2074,9 +2089,7 @@
                 method.dynamicSet(type, identNode.getName(), flags);
             }
         } else {
-            assert varNode.getType() == varNode.getName().getType() : "varNode type=" + varNode.getType() + " nametype=" + varNode.getName().getType() + " inittype=" + init.getType();
-
-            method.convert(varNode.getType()); // aw: convert moved here
+            method.convert(varNode.getName().getType()); // aw: convert moved here
             method.store(varSymbol);
         }
 
@@ -2087,11 +2100,11 @@
     public boolean enterWhileNode(final WhileNode whileNode) {
         lineNumber(whileNode);
 
-        final Node  test          = whileNode.getTest();
-        final Block body          = whileNode.getBody();
-        final Label breakLabel    = whileNode.getBreakLabel();
-        final Label continueLabel = whileNode.getContinueLabel();
-        final Label loopLabel     = new Label("loop");
+        final Expression test          = whileNode.getTest();
+        final Block      body          = whileNode.getBody();
+        final Label      breakLabel    = whileNode.getBreakLabel();
+        final Label      continueLabel = whileNode.getContinueLabel();
+        final Label      loopLabel     = new Label("loop");
 
         if (!whileNode.isDoWhile()) {
             method._goto(continueLabel);
@@ -2118,8 +2131,8 @@
 
     @Override
     public boolean enterWithNode(final WithNode withNode) {
-        final Node expression = withNode.getExpression();
-        final Node body       = withNode.getBody();
+        final Expression expression = withNode.getExpression();
+        final Node       body       = withNode.getBody();
 
         // It is possible to have a "pathological" case where the with block does not reference *any* identifiers. It's
         // pointless, but legal. In that case, if nothing else in the method forced the assignment of a slot to the
@@ -2194,7 +2207,7 @@
     // do this better with convert calls to method. TODO
     @Override
     public boolean enterCONVERT(final UnaryNode unaryNode) {
-        final Node rhs = unaryNode.rhs();
+        final Expression rhs = unaryNode.rhs();
         final Type to  = unaryNode.getType();
 
         if (to.isObject() && rhs instanceof LiteralNode) {
@@ -2231,11 +2244,11 @@
 
     @Override
     public boolean enterDECINC(final UnaryNode unaryNode) {
-        final Node      rhs         = unaryNode.rhs();
-        final Type      type        = unaryNode.getType();
-        final TokenType tokenType   = unaryNode.tokenType();
-        final boolean   isPostfix   = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
-        final boolean   isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
+        final Expression rhs         = unaryNode.rhs();
+        final Type       type        = unaryNode.getType();
+        final TokenType  tokenType   = unaryNode.tokenType();
+        final boolean    isPostfix   = tokenType == TokenType.DECPOSTFIX || tokenType == TokenType.INCPOSTFIX;
+        final boolean    isIncrement = tokenType == TokenType.INCPREFIX || tokenType == TokenType.INCPOSTFIX;
 
         assert !type.isObject();
 
@@ -2279,7 +2292,7 @@
 
     @Override
     public boolean enterDISCARD(final UnaryNode unaryNode) {
-        final Node rhs = unaryNode.rhs();
+        final Expression rhs = unaryNode.rhs();
 
         lc.pushDiscard(rhs);
         load(rhs);
@@ -2296,7 +2309,7 @@
     @Override
     public boolean enterNEW(final UnaryNode unaryNode) {
         final CallNode callNode = (CallNode)unaryNode.rhs();
-        final List args   = callNode.getArgs();
+        final List args   = callNode.getArgs();
 
         // Load function reference.
         load(callNode.getFunction()).convert(Type.OBJECT); // must detect type error
@@ -2309,7 +2322,7 @@
 
     @Override
     public boolean enterNOT(final UnaryNode unaryNode) {
-        final Node rhs = unaryNode.rhs();
+        final Expression rhs = unaryNode.rhs();
 
         load(rhs);
 
@@ -2335,19 +2348,26 @@
         return false;
     }
 
-    private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) {
+    @Override
+    public boolean enterVOID(final UnaryNode unaryNode) {
+        load(unaryNode.rhs()).pop();
+        method.loadUndefined(Type.OBJECT);
+
+        return false;
+    }
+
+    private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) {
         assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs);
         load(lhs);
         load(rhs);
         method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack?
         method.store(symbol);
-        return null;
     }
 
     @Override
     public boolean enterADD(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         final Type type = binaryNode.getType();
         if (type.isNumeric()) {
@@ -2363,8 +2383,8 @@
     }
 
     private boolean enterAND_OR(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         final Label skip = new Label("skip");
 
@@ -2391,8 +2411,8 @@
 
     @Override
     public boolean enterASSIGN(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         final Type lhsType = lhs.getType();
         final Type rhsType = rhs.getType();
@@ -2660,8 +2680,8 @@
     }
 
     private boolean enterComma(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         load(lhs);
         load(rhs);
@@ -2692,7 +2712,7 @@
         return false;
     }
 
-    private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) {
+    private boolean enterCmp(final Expression lhs, final Expression rhs, final Condition cond, final Type type, final Symbol symbol) {
         final Type lhsType = lhs.getType();
         final Type rhsType = rhs.getType();
 
@@ -2845,21 +2865,21 @@
 
     @Override
     public boolean enterTernaryNode(final TernaryNode ternaryNode) {
-        final Node lhs   = ternaryNode.lhs();
-        final Node rhs   = ternaryNode.rhs();
-        final Node third = ternaryNode.third();
+        final Expression test      = ternaryNode.getTest();
+        final Expression trueExpr  = ternaryNode.getTrueExpression();
+        final Expression falseExpr = ternaryNode.getFalseExpression();
 
         final Symbol symbol     = ternaryNode.getSymbol();
         final Label  falseLabel = new Label("ternary_false");
         final Label  exitLabel  = new Label("ternary_exit");
 
-        Type widest = Type.widest(rhs.getType(), third.getType());
-        if (rhs.getType().isArray() || third.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
+        Type widest = Type.widest(trueExpr.getType(), falseExpr.getType());
+        if (trueExpr.getType().isArray() || falseExpr.getType().isArray()) { //loadArray creates a Java array type on the stack, calls global allocate, which creates a native array type
             widest = Type.OBJECT;
         }
 
-        load(lhs);
-        assert lhs.getType().isBoolean() : "lhs in ternary must be boolean";
+        load(test);
+        assert test.getType().isBoolean() : "lhs in ternary must be boolean";
 
         // we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17
         // will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the
@@ -2867,11 +2887,11 @@
         // to early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to
         // do this property. Then we never need any conversions in CodeGenerator
         method.ifeq(falseLabel);
-        load(rhs);
+        load(trueExpr);
         method.convert(widest);
         method._goto(exitLabel);
         method.label(falseLabel);
-        load(third);
+        load(falseExpr);
         method.convert(widest);
         method.label(exitLabel);
         method.store(symbol);
@@ -2924,8 +2944,8 @@
      *
      * @param 
      */
-    private abstract class SelfModifyingStore extends Store {
-        protected SelfModifyingStore(final T assignNode, final Node target) {
+    private abstract class SelfModifyingStore extends Store {
+        protected SelfModifyingStore(final T assignNode, final Expression target) {
             super(assignNode, target);
         }
 
@@ -2938,13 +2958,13 @@
     /**
      * Helper class to generate stores
      */
-    private abstract class Store {
+    private abstract class Store {
 
         /** An assignment node, e.g. x += y */
         protected final T assignNode;
 
         /** The target node to store to, e.g. x */
-        private final Node target;
+        private final Expression target;
 
         /** How deep on the stack do the arguments go if this generates an indy call */
         private int depth;
@@ -2958,7 +2978,7 @@
          * @param assignNode the node representing the whole assignment
          * @param target     the target node of the assignment (destination)
          */
-        protected Store(final T assignNode, final Node target) {
+        protected Store(final T assignNode, final Expression target) {
             this.assignNode = assignNode;
             this.target = target;
         }
@@ -3001,8 +3021,8 @@
 
                 private void enterBaseNode() {
                     assert target instanceof BaseNode : "error - base node " + target + " must be instanceof BaseNode";
-                    final BaseNode baseNode = (BaseNode)target;
-                    final Node     base     = baseNode.getBase();
+                    final BaseNode   baseNode = (BaseNode)target;
+                    final Expression base     = baseNode.getBase();
 
                     load(base);
                     method.convert(Type.OBJECT);
@@ -3023,7 +3043,7 @@
                 public boolean enterIndexNode(final IndexNode node) {
                     enterBaseNode();
 
-                    final Node index = node.getIndex();
+                    final Expression index = node.getIndex();
                     // could be boolean here as well
                     load(index);
                     if (!index.getType().isNumeric()) {
@@ -3173,31 +3193,24 @@
             return;
         }
 
-        final boolean isLazy  = functionNode.isLazy();
-
-        new ObjectCreator(this, new ArrayList(), new ArrayList(), false, false) {
-            @Override
-            protected void makeObject(final MethodEmitter m) {
-                final String className = SCRIPTFUNCTION_IMPL_OBJECT;
-
-                m._new(className).dup();
-                loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap()));
-
-                if (isLazy || functionNode.needsParentScope()) {
-                    m.loadCompilerConstant(SCOPE);
-                } else {
-                    m.loadNull();
-                }
-                m.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
-            }
-        }.makeObject(method);
+        // Generate the object class and property map in case this function is ever used as constructor
+        final String      className          = SCRIPTFUNCTION_IMPL_OBJECT;
+        final int         fieldCount         = ObjectClassGenerator.getPaddedFieldCount(functionNode.countThisProperties());
+        final String      allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount));
+        final PropertyMap allocatorMap       = PropertyMap.newMap(null, 0, fieldCount, 0);
+
+        method._new(className).dup();
+        loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), allocatorClassName, allocatorMap));
+
+        if (functionNode.isLazy() || functionNode.needsParentScope()) {
+            method.loadCompilerConstant(SCOPE);
+        } else {
+            method.loadNull();
+        }
+        method.invoke(constructorNoLookup(className, RecompilableScriptFunctionData.class, ScriptObject.class));
     }
 
-    /*
-     * Globals are special. We cannot refer to any Global (or NativeObject) class by .class, as they are different
-     * for different contexts. As far as I can tell, the only NativeObject that we need to deal with like this
-     * is from the code pipeline is Global
-     */
+    // calls on Global class.
     private MethodEmitter globalInstance() {
         return method.invokestatic(GLOBAL_OBJECT, "instance", "()L" + GLOBAL_OBJECT + ';');
     }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java	Mon Jul 22 17:40:26 2013 -0700
@@ -18,17 +18,16 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-
 import jdk.nashorn.internal.codegen.types.Range;
 import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.CallNode;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.LexicalContext;
+import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ReturnNode;
 import jdk.nashorn.internal.ir.Symbol;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.TemporarySymbols;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
@@ -117,7 +116,7 @@
                         final FunctionNode parent = lc.getParentFunction(functionNode);
                         assert parent != null;
                         lc.setFlag(parent, FunctionNode.HAS_LAZY_CHILDREN);
-                        lc.setFlag(parent.getBody(), Block.NEEDS_SCOPE);
+                        lc.setBlockNeedsScope(parent.getBody());
                         lc.setFlag(functionNode, FunctionNode.IS_LAZY);
                         return functionNode;
                     }
@@ -258,17 +257,20 @@
 
                 @Override
                 public Node leaveDefault(final Node node) {
-                    final Symbol symbol = node.getSymbol();
-                    if (symbol != null) {
-                        final Range range  = symbol.getRange();
-                        final Type  symbolType = symbol.getSymbolType();
-                        if (!symbolType.isNumeric()) {
-                            return node;
-                        }
-                        final Type  rangeType  = range.getType();
-                        if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
-                            RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
-                            return node.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
+                    if(node instanceof Expression) {
+                        final Expression expr = (Expression)node;
+                        final Symbol symbol = expr.getSymbol();
+                        if (symbol != null) {
+                            final Range range  = symbol.getRange();
+                            final Type  symbolType = symbol.getSymbolType();
+                            if (!symbolType.isNumeric()) {
+                                return expr;
+                            }
+                            final Type  rangeType  = range.getType();
+                            if (!Type.areEquivalent(symbolType, rangeType) && Type.widest(symbolType, rangeType) == symbolType) { //we can narrow range
+                                RangeAnalyzer.LOG.info("[", lc.getCurrentFunction().getName(), "] ", symbol, " can be ", range.getType(), " ", symbol.getRange());
+                                return expr.setSymbol(lc, symbol.setTypeOverrideShared(range.getType(), compiler.getTemporarySymbols()));
+                            }
                         }
                     }
                     return node;
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java	Mon Jul 22 17:40:26 2013 -0700
@@ -528,8 +528,8 @@
         return this.env;
     }
 
-    private static String safeSourceName(final Source source) {
-        String baseName = new File(source.getName()).getName();
+    private String safeSourceName(final Source src) {
+        String baseName = new File(src.getName()).getName();
 
         final int index = baseName.lastIndexOf(".js");
         if (index != -1) {
@@ -537,6 +537,9 @@
         }
 
         baseName = baseName.replace('.', '_').replace('-', '_');
+        if (! env._loader_per_compile) {
+            baseName = baseName + installer.getUniqueScriptId();
+        }
         final String mangled = NameCodec.encode(baseName);
 
         return mangled != null ? mangled : baseName;
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Mon Jul 22 17:40:26 2013 -0700
@@ -100,10 +100,10 @@
     CALLEE(":callee", ScriptFunction.class),
 
     /** the varargs variable when necessary */
-    VARARGS(":varargs"),
+    VARARGS(":varargs", Object[].class),
 
     /** the arguments vector when necessary and the slot */
-    ARGUMENTS("arguments", Object.class, 2),
+    ARGUMENTS("arguments", ScriptObject.class, 2),
 
     /** prefix for iterators for for (x in ...) */
     ITERATOR_PREFIX(":i", Iterator.class),
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -26,15 +26,16 @@
 package jdk.nashorn.internal.codegen;
 
 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
-import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
+import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
 import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
 
 import java.util.Iterator;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptObject;
 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
@@ -48,6 +49,13 @@
  * @see jdk.nashorn.internal.ir.Node
  */
 public abstract class FieldObjectCreator extends ObjectCreator {
+
+    private         String        fieldObjectClassName;
+    private         Class      fieldObjectClass;
+    private         int           fieldCount;
+    private         int           paddedFieldCount;
+    private         int           paramCount;
+
     /** array of corresponding values to symbols (null for no values) */
     private final List values;
 
@@ -80,14 +88,9 @@
         super(codegen, keys, symbols, isScope, hasArguments);
         this.values        = values;
         this.callSiteFlags = codegen.getCallSiteFlags();
-    }
 
-    /**
-     * Loads the scope on the stack through the passed method emitter.
-     * @param method the method emitter to use
-     */
-    protected void loadScope(final MethodEmitter method) {
-        method.loadCompilerConstant(SCOPE);
+        countFields();
+        findClass();
     }
 
     /**
@@ -137,6 +140,13 @@
         }
     }
 
+    @Override
+    protected PropertyMap makeMap() {
+        assert propertyMap == null : "property map already initialized";
+        propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), fieldCount, paddedFieldCount);
+        return propertyMap;
+    }
+
     /**
      * Technique for loading an initial value. Defined by anonymous subclasses in code gen.
      *
@@ -173,4 +183,47 @@
         loadValue(value);
         method.dynamicSetIndex(callSiteFlags);
     }
+
+    /**
+     * Locate (or indirectly create) the object container class.
+     */
+    private void findClass() {
+        fieldObjectClassName = isScope() ?
+                ObjectClassGenerator.getClassName(fieldCount, paramCount) :
+                ObjectClassGenerator.getClassName(paddedFieldCount);
+
+        try {
+            this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
+        } catch (final ClassNotFoundException e) {
+            throw new AssertionError("Nashorn has encountered an internal error.  Structure can not be created.");
+        }
+    }
+
+    /**
+     * Get the class name for the object class,
+     * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
+     *
+     * @return script class name
+     */
+    String getClassName() {
+        return fieldObjectClassName;
+    }
+
+    /**
+     * Tally the number of fields and parameters.
+     */
+    private void countFields() {
+        for (final Symbol symbol : this.symbols) {
+            if (symbol != null) {
+                if (hasArguments() && symbol.isParam()) {
+                    symbol.setFieldIndex(paramCount++);
+                } else {
+                    symbol.setFieldIndex(fieldCount++);
+                }
+            }
+        }
+
+        paddedFieldCount = getPaddedFieldCount(fieldCount);
+    }
+
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java	Mon Jul 22 17:40:26 2013 -0700
@@ -31,7 +31,6 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
-
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.Assignment;
@@ -40,7 +39,8 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -147,9 +147,9 @@
      * strings etc as well.
      */
     @Override
-    public Node leaveADD(final BinaryNode binaryNode) {
-        final Node lhs = binaryNode.lhs();
-        final Node rhs = binaryNode.rhs();
+    public Expression leaveADD(final BinaryNode binaryNode) {
+        final Expression lhs = binaryNode.lhs();
+        final Expression rhs = binaryNode.rhs();
 
         final Type type = binaryNode.getType();
 
@@ -175,6 +175,14 @@
         if (destType == null) {
             destType = specBinaryNode.getType();
         }
+        // Register assignments to this object in case this is used as constructor
+        if (binaryNode.lhs() instanceof AccessNode) {
+            AccessNode accessNode = (AccessNode) binaryNode.lhs();
+
+            if (accessNode.getBase().getSymbol().isThis()) {
+                lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName());
+            }
+        }
         return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
     }
 
@@ -233,7 +241,7 @@
         return leaveASSIGN(binaryNode);
     }
 
-    private boolean symbolIsInteger(Node node) {
+    private boolean symbolIsInteger(final Expression node) {
         final Symbol symbol = node.getSymbol();
         assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource();
         return true;
@@ -365,7 +373,7 @@
 
     @Override
     public Node leaveCatchNode(final CatchNode catchNode) {
-        final Node exceptionCondition = catchNode.getExceptionCondition();
+        final Expression exceptionCondition = catchNode.getExceptionCondition();
         if (exceptionCondition != null) {
             return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
         }
@@ -373,16 +381,16 @@
     }
 
     @Override
-    public Node leaveExecuteNode(final ExecuteNode executeNode) {
+    public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
         temporarySymbols.reuse();
-        return executeNode.setExpression(discard(executeNode.getExpression()));
+        return expressionStatement.setExpression(discard(expressionStatement.getExpression()));
     }
 
     @Override
     public Node leaveForNode(final ForNode forNode) {
-        final Node init   = forNode.getInit();
-        final Node test   = forNode.getTest();
-        final Node modify = forNode.getModify();
+        final Expression init   = forNode.getInit();
+        final Expression test   = forNode.getTest();
+        final Expression modify = forNode.getModify();
 
         if (forNode.isForIn()) {
             return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400
@@ -407,10 +415,10 @@
         if (!functionNode.needsCallee()) {
             functionNode.compilerConstant(CALLEE).setNeedsSlot(false);
         }
-        // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope or its
-        // own scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope earlier than
-        // this phase.
-        if (!(functionNode.getBody().needsScope() || functionNode.needsParentScope())) {
+        // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope and none of
+        // its blocks create a scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope
+        // earlier than this phase.
+        if (!(functionNode.hasScopeBlock() || functionNode.needsParentScope())) {
             functionNode.compilerConstant(SCOPE).setNeedsSlot(false);
         }
 
@@ -432,13 +440,13 @@
     public boolean enterLiteralNode(final LiteralNode literalNode) {
         if (literalNode instanceof ArrayLiteralNode) {
             final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
-            final Node[]           array            = arrayLiteralNode.getValue();
+            final Expression[]     array            = arrayLiteralNode.getValue();
             final Type             elementType      = arrayLiteralNode.getElementType();
 
             for (int i = 0; i < array.length; i++) {
                 final Node element = array[i];
                 if (element != null) {
-                    array[i] = convert(element.accept(this), elementType);
+                    array[i] = convert((Expression)element.accept(this), elementType);
                 }
             }
         }
@@ -448,7 +456,7 @@
 
     @Override
     public Node leaveReturnNode(final ReturnNode returnNode) {
-        final Node expr = returnNode.getExpression();
+        final Expression expr = returnNode.getExpression();
         if (expr != null) {
             return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType()));
         }
@@ -457,8 +465,8 @@
 
     @Override
     public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
-        final List args = runtimeNode.getArgs();
-        for (final Node arg : args) {
+        final List args = runtimeNode.getArgs();
+        for (final Expression arg : args) {
             assert !arg.getType().isUnknown();
         }
         return runtimeNode;
@@ -472,12 +480,12 @@
             return switchNode;
         }
 
-        final Node           expression  = switchNode.getExpression();
+        final Expression     expression  = switchNode.getExpression();
         final List cases       = switchNode.getCases();
         final List newCases    = new ArrayList<>();
 
         for (final CaseNode caseNode : cases) {
-            final Node test = caseNode.getTest();
+            final Expression test = caseNode.getTest();
             newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode);
         }
 
@@ -488,7 +496,7 @@
 
     @Override
     public Node leaveTernaryNode(final TernaryNode ternaryNode) {
-        return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
+        return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN));
     }
 
     @Override
@@ -498,16 +506,16 @@
 
     @Override
     public Node leaveVarNode(final VarNode varNode) {
-        final Node init = varNode.getInit();
+        final Expression init = varNode.getInit();
         if (init != null) {
             final SpecializedNode specialized = specialize(varNode);
             final VarNode specVarNode = (VarNode)specialized.node;
             Type destType = specialized.type;
             if (destType == null) {
-                destType = specVarNode.getType();
+                destType = specVarNode.getName().getType();
             }
-            assert specVarNode.hasType() : specVarNode + " doesn't have a type";
-            final Node convertedInit = convert(init, destType);
+            assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type";
+            final Expression convertedInit = convert(init, destType);
             temporarySymbols.reuse();
             return specVarNode.setInit(convertedInit);
         }
@@ -517,7 +525,7 @@
 
     @Override
     public Node leaveWhileNode(final WhileNode whileNode) {
-        final Node test = whileNode.getTest();
+        final Expression test = whileNode.getTest();
         if (test != null) {
             return whileNode.setTest(lc, convert(test, Type.BOOLEAN));
         }
@@ -592,8 +600,8 @@
      */
     @SuppressWarnings("fallthrough")
     private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
-        final Node lhs    = binaryNode.lhs();
-        final Node rhs    = binaryNode.rhs();
+        final Expression lhs    = binaryNode.lhs();
+        final Expression rhs    = binaryNode.rhs();
 
         Type widest = Type.widest(lhs.getType(), rhs.getType());
 
@@ -689,10 +697,10 @@
         }
     }
 
-     SpecializedNode specialize(final Assignment assignment) {
+     SpecializedNode specialize(final Assignment assignment) {
         final Node node = ((Node)assignment);
         final T lhs = assignment.getAssignmentDest();
-        final Node rhs = assignment.getAssignmentSource();
+        final Expression rhs = assignment.getAssignmentSource();
 
         if (!canHaveCallSiteType(lhs)) {
             return new SpecializedNode(node, null);
@@ -711,8 +719,16 @@
         }
 
         final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
-        final Node typePropagatedNode = propagateType(newNode, to);
-
+        final Node typePropagatedNode;
+        if(newNode instanceof Expression) {
+            typePropagatedNode = propagateType((Expression)newNode, to);
+        } else if(newNode instanceof VarNode) {
+            // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead.
+            final VarNode varNode = (VarNode)newNode;
+            typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to));
+        } else {
+            throw new AssertionError();
+        }
         return new SpecializedNode(typePropagatedNode, to);
     }
 
@@ -752,7 +768,7 @@
      * @param to      new type
      */
     @SuppressWarnings("unchecked")
-     T setTypeOverride(final T node, final Type to) {
+     T setTypeOverride(final T node, final Type to) {
         final Type from = node.getType();
         if (!node.getType().equals(to)) {
             LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to);
@@ -781,7 +797,7 @@
      * @param to   destination type
      * @return     conversion node
      */
-    private Node convert(final Node node, final Type to) {
+    private Expression convert(final Expression node, final Type to) {
         assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass();
         assert node != null : "node is null";
         assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction();
@@ -797,7 +813,7 @@
             return node;
         }
 
-        Node resultNode = node;
+        Expression resultNode = node;
 
         if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) {
             final LiteralNode newNode = new LiteralNodeConstantEvaluator((LiteralNode)node, to).eval();
@@ -821,9 +837,9 @@
         return temporarySymbols.ensureSymbol(lc, to, resultNode);
     }
 
-    private static Node discard(final Node node) {
+    private static Expression discard(final Expression node) {
         if (node.getSymbol() != null) {
-            final Node discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
+            final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node);
             //discard never has a symbol in the discard node - then it would be a nop
             assert !node.isTerminal();
             return discard;
@@ -846,7 +862,7 @@
      * @param node
      * @param to
      */
-    private Node propagateType(final Node node, final Type to) {
+    private Expression propagateType(final Expression node, final Type to) {
         Symbol symbol = node.getSymbol();
         if (symbol.isTemp() && symbol.getSymbolType() != to) {
             symbol = symbol.setTypeOverrideShared(to, temporarySymbols);
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java	Mon Jul 22 17:40:26 2013 -0700
@@ -28,8 +28,8 @@
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.BlockStatement;
 import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
 import jdk.nashorn.internal.ir.IfNode;
@@ -91,7 +91,7 @@
         if (test instanceof LiteralNode) {
             final Block shortCut = ((LiteralNode)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
             if (shortCut != null) {
-                return new ExecuteNode(shortCut.getLineNumber(), shortCut.getToken(), shortCut.getFinish(), shortCut);
+                return new BlockStatement(ifNode.getLineNumber(), shortCut);
             }
             return new EmptyNode(ifNode);
         }
@@ -100,9 +100,9 @@
 
     @Override
     public Node leaveTernaryNode(final TernaryNode ternaryNode) {
-        final Node test = ternaryNode.lhs();
+        final Node test = ternaryNode.getTest();
         if (test instanceof LiteralNode) {
-            return ((LiteralNode)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
+            return ((LiteralNode)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression();
         }
         return ternaryNode;
     }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java	Mon Jul 22 17:40:26 2013 -0700
@@ -31,8 +31,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
 
@@ -63,7 +63,7 @@
      * @param retType   what is the return type
      * @param args      argument list of AST Nodes
      */
-    public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List args) {
+    public FunctionSignature(final boolean hasSelf, final boolean hasCallee, final Type retType, final List args) {
         this(hasSelf, hasCallee, retType, FunctionSignature.typeArray(args));
     }
 
@@ -167,7 +167,7 @@
      *
      * @return the array of types
      */
-    private static Type[] typeArray(final List args) {
+    private static Type[] typeArray(final List args) {
         if (args == null) {
             return null;
         }
@@ -175,7 +175,7 @@
         final Type[] typeArray = new Type[args.size()];
 
         int pos = 0;
-        for (final Node arg : args) {
+        for (final Expression arg : args) {
             typeArray[pos++] = arg.getType();
         }
 
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/Lower.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java	Mon Jul 22 17:40:26 2013 -0700
@@ -32,16 +32,19 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.ListIterator;
 import jdk.nashorn.internal.ir.BaseNode;
 import jdk.nashorn.internal.ir.BinaryNode;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.BlockLexicalContext;
+import jdk.nashorn.internal.ir.BlockStatement;
 import jdk.nashorn.internal.ir.BreakNode;
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.EmptyNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -115,6 +118,21 @@
                 }
                 return newStatements;
             }
+
+            @Override
+            protected Block afterSetStatements(final Block block) {
+                final List stmts = block.getStatements();
+                for(final ListIterator li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
+                    final Statement stmt = li.previous();
+                    // popStatements() guarantees that the only thing after a terminal statement are uninitialized
+                    // VarNodes. We skip past those, and set the terminal state of the block to the value of the
+                    // terminal state of the first statement that is not an uninitialized VarNode.
+                    if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
+                        return block.setIsTerminal(this, stmt.isTerminal());
+                    }
+                }
+                return block.setIsTerminal(this, false);
+            }
         });
     }
 
@@ -122,7 +140,7 @@
     public boolean enterBlock(final Block block) {
         final FunctionNode   function = lc.getCurrentFunction();
         if (lc.isFunctionBody() && function.isProgram() && !function.hasDeclaredFunctions()) {
-            new ExecuteNode(block.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
+            new ExpressionStatement(function.getLineNumber(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this);
         }
         return true;
     }
@@ -132,24 +150,20 @@
         //now we have committed the entire statement list to the block, but we need to truncate
         //whatever is after the last terminal. block append won't append past it
 
-        Statement last = lc.getLastStatement();
 
         if (lc.isFunctionBody()) {
             final FunctionNode currentFunction = lc.getCurrentFunction();
             final boolean isProgram = currentFunction.isProgram();
+            final Statement last = lc.getLastStatement();
             final ReturnNode returnNode = new ReturnNode(
-                last == null ? block.getLineNumber() : last.getLineNumber(), //TODO?
+                last == null ? currentFunction.getLineNumber() : last.getLineNumber(), //TODO?
                 currentFunction.getToken(),
                 currentFunction.getFinish(),
                 isProgram ?
                     compilerConstant(RETURN) :
                     LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED));
 
-            last = (Statement)returnNode.accept(this);
-        }
-
-        if (last != null && last.isTerminal()) {
-            return block.setIsTerminal(lc, true);
+            returnNode.accept(this);
         }
 
         return block;
@@ -183,23 +197,21 @@
     }
 
     @Override
-    public Node leaveExecuteNode(final ExecuteNode executeNode) {
-        final Node expr = executeNode.getExpression();
-        ExecuteNode node = executeNode;
+    public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
+        final Expression expr = expressionStatement.getExpression();
+        ExpressionStatement node = expressionStatement;
 
         final FunctionNode currentFunction = lc.getCurrentFunction();
 
         if (currentFunction.isProgram()) {
-            if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
-                if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
-                    node = executeNode.setExpression(
-                        new BinaryNode(
-                            Token.recast(
-                                executeNode.getToken(),
-                                TokenType.ASSIGN),
-                            compilerConstant(RETURN),
-                        expr));
-                }
+            if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
+                node = expressionStatement.setExpression(
+                    new BinaryNode(
+                        Token.recast(
+                            expressionStatement.getToken(),
+                            TokenType.ASSIGN),
+                        compilerConstant(RETURN),
+                    expr));
             }
         }
 
@@ -207,6 +219,11 @@
     }
 
     @Override
+    public Node leaveBlockStatement(BlockStatement blockStatement) {
+        return addStatement(blockStatement);
+    }
+
+    @Override
     public Node leaveForNode(final ForNode forNode) {
         ForNode newForNode = forNode;
 
@@ -290,11 +307,11 @@
 
         final IdentNode exception = new IdentNode(token, finish, lc.getCurrentFunction().uniqueName("catch_all"));
 
-        final Block catchBody = new Block(lineNumber, token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
+        final Block catchBody = new Block(token, finish, new ThrowNode(lineNumber, token, finish, new IdentNode(exception), ThrowNode.IS_SYNTHETIC_RETHROW)).
                 setIsTerminal(lc, true); //ends with throw, so terminal
 
         final CatchNode catchAllNode  = new CatchNode(lineNumber, token, finish, new IdentNode(exception), null, catchBody, CatchNode.IS_SYNTHETIC_RETHROW);
-        final Block     catchAllBlock = new Block(lineNumber, token, finish, catchAllNode);
+        final Block     catchAllBlock = new Block(token, finish, catchAllNode);
 
         //catchallblock -> catchallnode (catchnode) -> exception -> throw
 
@@ -343,14 +360,14 @@
                     if (!isTerminal(newStatements)) {
                         newStatements.add(throwNode);
                     }
-                    return new Block(throwNode.getLineNumber(), throwNode.getToken(), throwNode.getFinish(), newStatements);
+                    return BlockStatement.createReplacement(throwNode, newStatements);
                 }
                 return throwNode;
             }
 
             @Override
             public Node leaveBreakNode(final BreakNode breakNode) {
-                return copy(breakNode, Lower.this.lc.getBreakable(breakNode.getLabel()));
+                return copy(breakNode, (Node)Lower.this.lc.getBreakable(breakNode.getLabel()));
             }
 
             @Override
@@ -360,15 +377,15 @@
 
             @Override
             public Node leaveReturnNode(final ReturnNode returnNode) {
-                final Node  expr  = returnNode.getExpression();
+                final Expression expr  = returnNode.getExpression();
                 final List newStatements = new ArrayList<>();
 
-                final Node resultNode;
+                final Expression resultNode;
                 if (expr != null) {
                     //we need to evaluate the result of the return in case it is complex while
                     //still in the try block, store it in a result value and return it afterwards
                     resultNode = new IdentNode(Lower.this.compilerConstant(RETURN));
-                    newStatements.add(new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
+                    newStatements.add(new ExpressionStatement(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new BinaryNode(Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr)));
                 } else {
                     resultNode = null;
                 }
@@ -378,7 +395,7 @@
                     newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode));
                 }
 
-                return new ExecuteNode(returnNode.getLineNumber(), returnNode.getToken(), returnNode.getFinish(), new Block(returnNode.getLineNumber(), returnNode.getToken(), lc.getCurrentBlock().getFinish(), newStatements));
+                return BlockStatement.createReplacement(returnNode, lc.getCurrentBlock().getFinish(), newStatements);
             }
 
             private Node copy(final Statement endpoint, final Node targetNode) {
@@ -387,7 +404,7 @@
                     if (!isTerminal(newStatements)) {
                         newStatements.add(endpoint);
                     }
-                    return new ExecuteNode(endpoint.getLineNumber(), endpoint.getToken(), endpoint.getFinish(), new Block(endpoint.getLineNumber(), endpoint.getToken(), finish, newStatements));
+                    return BlockStatement.createReplacement(endpoint, finish, newStatements);
                 }
                 return endpoint;
             }
@@ -449,7 +466,7 @@
         if (tryNode.getCatchBlocks().isEmpty()) {
             newTryNode = tryNode.setFinallyBody(null);
         } else {
-            Block outerBody = new Block(tryNode.getLineNumber(), tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null))));
+            Block outerBody = new Block(tryNode.getToken(), tryNode.getFinish(), new ArrayList(Arrays.asList(tryNode.setFinallyBody(null))));
             newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null);
         }
 
@@ -466,7 +483,7 @@
     public Node leaveVarNode(final VarNode varNode) {
         addStatement(varNode);
         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && lc.getCurrentFunction().isProgram()) {
-            new ExecuteNode(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
+            new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
         }
         return varNode;
     }
@@ -499,7 +516,7 @@
      * @param function function called by a CallNode
      * @return transformed node to marker function or identity if not ident/access/indexnode
      */
-    private static Node markerFunction(final Node function) {
+    private static Expression markerFunction(final Expression function) {
         if (function instanceof IdentNode) {
             return ((IdentNode)function).setIsFunction();
         } else if (function instanceof BaseNode) {
@@ -541,15 +558,15 @@
     private CallNode checkEval(final CallNode callNode) {
         if (callNode.getFunction() instanceof IdentNode) {
 
-            final List args   = callNode.getArgs();
-            final IdentNode  callee = (IdentNode)callNode.getFunction();
+            final List args = callNode.getArgs();
+            final IdentNode callee = (IdentNode)callNode.getFunction();
 
             // 'eval' call with at least one argument
             if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) {
                 final FunctionNode currentFunction = lc.getCurrentFunction();
                 return callNode.setEvalArgs(
                     new CallNode.EvalArgs(
-                        ensureUniqueNamesIn(args.get(0)).accept(this),
+                        (Expression)ensureUniqueNamesIn(args.get(0)).accept(this),
                         compilerConstant(THIS),
                         evalLocation(callee),
                         currentFunction.isStrict()));
@@ -618,7 +635,7 @@
      * @param expression expression to check for internal symbol
      * @return true if internal, false otherwise
      */
-    private static boolean isInternalExpression(final Node expression) {
+    private static boolean isInternalExpression(final Expression expression) {
         final Symbol symbol = expression.getSymbol();
         return symbol != null && symbol.isInternal();
     }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -41,10 +41,10 @@
     private final Class structure;
 
     /** key set for object map */
-    private final String[] keys;
+    final List keys;
 
     /** corresponding symbol set for object map */
-    private final Symbol[] symbols;
+    final List symbols;
 
     /**
      * Constructor
@@ -54,11 +54,9 @@
      * @param symbols   list of symbols for map
      */
     MapCreator(final Class structure, final List keys, final List symbols) {
-        final int size   = keys.size();
-
         this.structure = structure;
-        this.keys      = keys.toArray(new String[size]);
-        this.symbols   = symbols.toArray(new Symbol[size]);
+        this.keys      = keys;
+        this.symbols   = symbols;
     }
 
     /**
@@ -70,21 +68,37 @@
      *
      * @return New map populated with accessor properties.
      */
-    PropertyMap makeMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
+    PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum) {
         final List properties = new ArrayList<>();
-
         assert keys != null;
 
-        for (int i = 0; i < keys.length; i++) {
-            final String key    = keys[i];
-            final Symbol symbol = symbols[i];
+        for (int i = 0, length = keys.size(); i < length; i++) {
+            final String key    = keys.get(i);
+            final Symbol symbol = symbols.get(i);
 
             if (symbol != null && !ArrayIndex.isIntArrayIndex(key)) {
                 properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex()));
             }
         }
 
-        return PropertyMap.newMap(structure, properties, fieldCount, fieldMaximum);
+        return PropertyMap.newMap(properties, fieldCount, fieldMaximum, 0);
+    }
+
+    PropertyMap makeSpillMap(final boolean hasArguments) {
+        final List properties = new ArrayList<>();
+        int spillIndex = 0;
+        assert keys != null;
+
+        for (int i = 0, length = keys.size(); i < length; i++) {
+            final String key    = keys.get(i);
+            final Symbol symbol = symbols.get(i);
+
+            if (symbol != null && !ArrayIndex.isIntArrayIndex(key)) {
+                properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), spillIndex++));
+            }
+        }
+
+        return PropertyMap.newMap(properties, 0, 0, spillIndex);
     }
 
     /**
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -74,11 +74,6 @@
     static final int FIELD_PADDING  = 4;
 
     /**
-     * Rounding when calculating the number of fields.
-     */
-    static final int FIELD_ROUNDING = 4;
-
-    /**
      * Debug field logger
      * Should we print debugging information for fields when they are generated and getters/setters are called?
      */
@@ -325,7 +320,6 @@
         final List initFields   = addFields(classEmitter, fieldCount);
 
         final MethodEmitter init = newInitMethod(classEmitter);
-        initializeToUndefined(init, className, initFields);
         init.returnVoid();
         init.end();
 
@@ -441,13 +435,13 @@
      * @return Open method emitter.
      */
     private static MethodEmitter newInitScopeWithArgumentsMethod(final ClassEmitter classEmitter) {
-        final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, Object.class);
+        final MethodEmitter init = classEmitter.init(PropertyMap.class, ScriptObject.class, ScriptObject.class);
         init.begin();
         init.load(Type.OBJECT, JAVA_THIS.slot());
         init.load(Type.OBJECT, INIT_MAP.slot());
         init.load(Type.OBJECT, INIT_SCOPE.slot());
         init.load(Type.OBJECT, INIT_ARGUMENTS.slot());
-        init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, Object.class));
+        init.invoke(constructorNoLookup(FunctionScope.class, PropertyMap.class, ScriptObject.class, ScriptObject.class));
 
         return init;
     }
@@ -709,6 +703,15 @@
         }
     }
 
+    /**
+     * Add padding to field count to avoid creating too many classes and have some spare fields
+     * @param count the field count
+     * @return the padded field count
+     */
+    static int getPaddedFieldCount(final int count) {
+        return count / FIELD_PADDING * FIELD_PADDING + FIELD_PADDING;
+    }
+
     //
     // Provide generic getters and setters for undefined types. If a type is undefined, all
     // and marshals the set to the correct setter depending on the type of the value being set.
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -25,10 +25,10 @@
 
 package jdk.nashorn.internal.codegen;
 
+import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE;
+
 import java.util.List;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING;
 import jdk.nashorn.internal.ir.Symbol;
-import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.PropertyMap;
 
 /**
@@ -36,9 +36,6 @@
  */
 public abstract class ObjectCreator {
 
-    /** Compile unit for this ObjectCreator, see CompileUnit */
-    //protected final CompileUnit   compileUnit;
-
     /** List of keys to initiate in this ObjectCreator */
     protected final List  keys;
 
@@ -50,12 +47,7 @@
 
     private   final boolean       isScope;
     private   final boolean       hasArguments;
-    private         int           fieldCount;
-    private         int           paddedFieldCount;
-    private         int           paramCount;
-    private         String        fieldObjectClassName;
-    private         Class      fieldObjectClass;
-    private         PropertyMap   propertyMap;
+    protected       PropertyMap   propertyMap;
 
     /**
      * Constructor
@@ -72,41 +64,6 @@
         this.symbols       = symbols;
         this.isScope       = isScope;
         this.hasArguments  = hasArguments;
-
-        countFields();
-        findClass();
-    }
-
-    /**
-     * Tally the number of fields and parameters.
-     */
-    private void countFields() {
-        for (final Symbol symbol : this.symbols) {
-            if (symbol != null) {
-                if (hasArguments() && symbol.isParam()) {
-                    symbol.setFieldIndex(paramCount++);
-                } else {
-                    symbol.setFieldIndex(fieldCount++);
-                }
-            }
-        }
-
-        paddedFieldCount = fieldCount + FIELD_PADDING;
-    }
-
-    /**
-     * Locate (or indirectly create) the object container class.
-     */
-    private void findClass() {
-        fieldObjectClassName = isScope() ?
-            ObjectClassGenerator.getClassName(fieldCount, paramCount) :
-            ObjectClassGenerator.getClassName(paddedFieldCount);
-
-        try {
-            this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
-        } catch (final ClassNotFoundException e) {
-            throw new AssertionError("Nashorn has encountered an internal error.  Structure can not be created.");
-        }
     }
 
     /**
@@ -116,6 +73,12 @@
     protected abstract void makeObject(final MethodEmitter method);
 
     /**
+     * Construct the property map appropriate for the object.
+     * @return the newly created property map
+     */
+    protected abstract PropertyMap makeMap();
+
+    /**
      * Create a new MapCreator
      * @param clazz type of MapCreator
      * @return map creator instantiated by type
@@ -125,12 +88,11 @@
     }
 
     /**
-     * Construct the property map appropriate for the object.
-     * @return the newly created property map
+     * Loads the scope on the stack through the passed method emitter.
+     * @param method the method emitter to use
      */
-    protected PropertyMap makeMap() {
-        propertyMap = newMapCreator(fieldObjectClass).makeMap(hasArguments(), fieldCount, paddedFieldCount);
-        return propertyMap;
+    protected void loadScope(final MethodEmitter method) {
+        method.loadCompilerConstant(SCOPE);
     }
 
     /**
@@ -144,16 +106,6 @@
     }
 
     /**
-     * Get the class name for the object class,
-     * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
-     *
-     * @return script class name
-     */
-    String getClassName() {
-        return fieldObjectClassName;
-    }
-
-    /**
      * Is this a scope object
      * @return true if scope
      */
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/RangeAnalyzer.java	Mon Jul 22 17:40:26 2013 -0700
@@ -28,11 +28,11 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
-
 import jdk.nashorn.internal.codegen.types.Range;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Assignment;
 import jdk.nashorn.internal.ir.BinaryNode;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.IdentNode;
 import jdk.nashorn.internal.ir.LexicalContext;
@@ -87,7 +87,7 @@
     }
 
     //destination visited
-    private Symbol setRange(final Node dest, final Range range) {
+    private Symbol setRange(final Expression dest, final Range range) {
         if (range.isUnknown()) {
             return null;
         }
@@ -352,7 +352,6 @@
             range = range.isUnknown() ? Range.createGenericRange() : range;
 
             setRange(node.getName(), range);
-            setRange(node, range);
         }
 
         return node;
@@ -438,12 +437,12 @@
      * @return
      */
     private static Symbol findLoopCounter(final LoopNode node) {
-        final Node test = node.getTest();
+        final Expression test = node.getTest();
 
         if (test != null && test.isComparison()) {
             final BinaryNode binaryNode = (BinaryNode)test;
-            final Node lhs = binaryNode.lhs();
-            final Node rhs = binaryNode.rhs();
+            final Expression lhs = binaryNode.lhs();
+            final Expression rhs = binaryNode.rhs();
 
             //detect ident cmp int_literal
             if (lhs instanceof IdentNode && rhs instanceof LiteralNode && ((LiteralNode)rhs).getType().isInteger()) {
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Mon Jul 22 17:40:26 2013 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2010-2013, 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.codegen;
+
+import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
+import static jdk.nashorn.internal.codegen.types.Type.OBJECT;
+
+import java.util.List;
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.runtime.Property;
+import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.scripts.JO;
+
+/**
+ * An object creator that uses spill properties.
+ */
+public class SpillObjectCreator extends ObjectCreator {
+
+    private final List values;
+
+    /**
+     * Constructor
+     *
+     * @param codegen  code generator
+     * @param keys     keys for fields in object
+     * @param symbols  symbols for fields in object
+     * @param values   list of values corresponding to keys
+     */
+    protected SpillObjectCreator(final CodeGenerator codegen, final List keys, final List symbols, final List values) {
+        super(codegen, keys, symbols, false, false);
+        this.values = values;
+        makeMap();
+    }
+
+    @Override
+    protected void makeObject(final MethodEmitter method) {
+        assert !isScope() : "spill scope objects are not currently supported";
+
+        final int      length       = keys.size();
+        final Object[] presetValues = new Object[propertyMap.size()];
+        final Class    clazz        = JO.class;
+
+        // Compute constant values
+        for (int i = 0; i < length; i++) {
+            final String key = keys.get(i);
+            final Property property = propertyMap.findProperty(key);
+
+            if (property != null) {
+                presetValues[property.getSlot()] = LiteralNode.objectAsConstant(values.get(i));
+            }
+        }
+
+        method._new(clazz).dup();
+        codegen.loadConstant(propertyMap);
+
+        method.invoke(constructorNoLookup(JO.class, PropertyMap.class));
+
+        method.dup();
+        codegen.loadConstant(presetValues);
+
+        // Create properties with non-constant values
+        for (int i = 0; i < length; i++) {
+            final String key = keys.get(i);
+            final Property property = propertyMap.findProperty(key);
+
+            if (property != null && presetValues[property.getSlot()] == LiteralNode.POSTSET_MARKER) {
+                method.dup();
+                method.load(property.getSlot());
+                codegen.load(values.get(i)).convert(OBJECT);
+                method.arraystore();
+                presetValues[property.getSlot()] = null;
+            }
+        }
+
+        method.putField(Type.typeFor(ScriptObject.class).getInternalName(), "spill", Type.OBJECT_ARRAY.getDescriptor());
+        final int callSiteFlags = codegen.getCallSiteFlags();
+
+        // Assign properties with valid array index keys
+        for (int i = 0; i < length; i++) {
+            final String key = keys.get(i);
+            final Property property = propertyMap.findProperty(key);
+            final Expression value = values.get(i);
+
+            if (property == null && value != null) {
+                method.dup();
+                method.load(keys.get(i));
+                codegen.load(value);
+                method.dynamicSetIndex(callSiteFlags);
+            }
+        }
+    }
+
+    @Override
+    protected PropertyMap makeMap() {
+        assert propertyMap == null : "property map already initialized";
+
+        propertyMap = new MapCreator(JO.class, keys, symbols) {
+            @Override
+            protected int getPropertyFlags(Symbol symbol, boolean hasArguments) {
+                return super.getPropertyFlags(symbol, hasArguments) | Property.IS_SPILL | Property.IS_ALWAYS_OBJECT;
+            }
+        }.makeSpillMap(false);
+
+        return propertyMap;
+    }
+}
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java	Mon Jul 22 17:40:26 2013 -0700
@@ -31,7 +31,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -221,14 +220,13 @@
      * @return New split node.
      */
     private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List statements, final long weight) {
-        final int    lineNumber = parent.getLineNumber();
         final long   token      = parent.getToken();
         final int    finish     = parent.getFinish();
         final String name       = function.uniqueName(SPLIT_PREFIX.symbolName());
 
-        final Block newBlock = new Block(lineNumber, token, finish, statements);
+        final Block newBlock = new Block(token, finish, statements);
 
-        return new SplitNode(lineNumber, name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
+        return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT));
     }
 
     @Override
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java	Mon Jul 22 17:40:26 2013 -0700
@@ -27,7 +27,6 @@
 
 import java.util.List;
 import java.util.Map;
-
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.AccessNode;
 import jdk.nashorn.internal.ir.BinaryNode;
@@ -36,7 +35,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CatchNode;
 import jdk.nashorn.internal.ir.ContinueNode;
-import jdk.nashorn.internal.ir.ExecuteNode;
+import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
@@ -158,8 +157,8 @@
     }
 
     @Override
-    public Node leaveExecuteNode(final ExecuteNode executeNode) {
-        return executeNode;
+    public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
+        return expressionStatement;
     }
 
     @Override
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java	Mon Jul 22 17:40:26 2013 -0700
@@ -47,9 +47,8 @@
 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
 
 import java.lang.invoke.MethodHandle;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import jdk.internal.org.objectweb.asm.MethodVisitor;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 
@@ -548,19 +547,19 @@
      * @return the Type representing this class
      */
     public static Type typeFor(final Class clazz) {
-        Type type = cache.get(clazz);
-
-        if (type == null) {
-            assert !clazz.isPrimitive() || clazz == void.class;
-            if (clazz.isArray()) {
-                type = new ArrayType(clazz);
-            } else {
-                type = new ObjectType(clazz);
-            }
-            cache.put(clazz, type);
+        final Type type = cache.get(clazz);
+        if(type != null) {
+            return type;
         }
-
-        return type;
+        assert !clazz.isPrimitive() || clazz == void.class;
+        final Type newType;
+        if (clazz.isArray()) {
+            newType = new ArrayType(clazz);
+        } else {
+            newType = new ObjectType(clazz);
+        }
+        final Type existingType = cache.putIfAbsent(clazz, newType);
+        return existingType == null ? newType : existingType;
     }
 
     @Override
@@ -663,35 +662,38 @@
         }
     }
 
+    /** Mappings between java classes and their Type singletons */
+    private static final ConcurrentMap, Type> cache = new ConcurrentHashMap<>();
+
     /**
      * This is the boolean singleton, used for all boolean types
      */
-    public static final Type BOOLEAN = new BooleanType();
+    public static final Type BOOLEAN = putInCache(new BooleanType());
 
     /**
      * This is an integer type, i.e INT, INT32.
      */
-    public static final Type INT = new IntType();
+    public static final Type INT = putInCache(new IntType());
 
     /**
      * This is the number singleton, used for all number types
      */
-    public static final Type NUMBER = new NumberType();
+    public static final Type NUMBER = putInCache(new NumberType());
 
     /**
      * This is the long singleton, used for all long types
      */
-    public static final Type LONG = new LongType();
+    public static final Type LONG = putInCache(new LongType());
 
     /**
      * A string singleton
      */
-    public static final Type STRING = new ObjectType(String.class);
+    public static final Type STRING = putInCache(new ObjectType(String.class));
 
     /**
      * This is the object singleton, used for all object types
      */
-    public static final Type OBJECT = new ObjectType();
+    public static final Type OBJECT = putInCache(new ObjectType());
 
     /**
      * This is the singleton for integer arrays
@@ -775,13 +777,13 @@
     };
 
     /** Singleton for method handle arrays used for properties etc. */
-    public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(MethodHandle[].class);
+    public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
 
     /** This is the singleton for string arrays */
-    public static final ArrayType STRING_ARRAY = new ArrayType(String[].class);
+    public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
 
     /** This is the singleton for object arrays */
-    public static final ArrayType OBJECT_ARRAY = new ArrayType(Object[].class);
+    public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
 
     /** This type, always an object type, just a toString override */
     public static final Type THIS = new ObjectType() {
@@ -855,18 +857,8 @@
         }
     };
 
-    /** Mappings between java classes and their Type singletons */
-    private static final Map, Type> cache = Collections.synchronizedMap(new HashMap, Type>());
-
-    //TODO may need to be cleared, as all types are retained throughout code generation
-    static {
-        cache.put(BOOLEAN.getTypeClass(), BOOLEAN);
-        cache.put(INT.getTypeClass(),     INT);
-        cache.put(LONG.getTypeClass(),    LONG);
-        cache.put(NUMBER.getTypeClass(),  NUMBER);
-        cache.put(STRING.getTypeClass(),  STRING);
-        cache.put(OBJECT.getTypeClass(),  OBJECT);
-        cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY);
+    private static  T putInCache(T type) {
+        cache.put(type.getTypeClass(), type);
+        return type;
     }
-
 }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/ir/AccessNode.java
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java	Mon Jul 22 17:40:26 2013 -0700
@@ -45,12 +45,12 @@
      * @param base      base node
      * @param property  property
      */
-    public AccessNode(final long token, final int finish, final Node base, final IdentNode property) {
+    public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) {
         super(token, finish, base, false, false);
         this.property = property.setIsPropertyName();
     }
 
-    private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
+    private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) {
         super(accessNode, base, isFunction, hasCallSiteType);
         this.property = property;
     }
@@ -63,7 +63,7 @@
     public Node accept(final NodeVisitor visitor) {
         if (visitor.enterAccessNode(this)) {
             return visitor.leaveAccessNode(
-                setBase(base.accept(visitor)).
+                setBase((Expression)base.accept(visitor)).
                 setProperty((IdentNode)property.accept(visitor)));
         }
         return this;
@@ -103,7 +103,7 @@
         return property;
     }
 
-    private AccessNode setBase(final Node base) {
+    private AccessNode setBase(final Expression base) {
         if (this.base == base) {
             return this;
         }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/ir/Assignment.java
--- a/nashorn/src/jdk/nashorn/internal/ir/Assignment.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/Assignment.java	Mon Jul 22 17:40:26 2013 -0700
@@ -31,7 +31,7 @@
  *
  * @param  the destination type
  */
-public interface Assignment {
+public interface Assignment {
 
     /**
      * Get assignment destination
@@ -45,7 +45,7 @@
      *
      * @return get the assignment source node
      */
-    public Node getAssignmentSource();
+    public Expression getAssignmentSource();
 
     /**
      * Set assignment destination node.
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/ir/BaseNode.java
--- a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java	Mon Jul 22 17:40:26 2013 -0700
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.ir;
 
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
+
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -37,10 +38,10 @@
  * @see IndexNode
  */
 @Immutable
-public abstract class BaseNode extends Node implements FunctionCall, TypeOverride {
+public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride {
 
     /** Base Node. */
-    protected final Node base;
+    protected final Expression base;
 
     private final boolean isFunction;
 
@@ -55,7 +56,7 @@
      * @param isFunction is this a function
      * @param hasCallSiteType does this access have a callsite type
      */
-    public BaseNode(final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+    public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
         super(token, base.getStart(), finish);
         this.base            = base;
         this.isFunction      = isFunction;
@@ -69,7 +70,7 @@
      * @param isFunction is this a function
      * @param hasCallSiteType does this access have a callsite type
      */
-    protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) {
+    protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) {
         super(baseNode);
         this.base            = base;
         this.isFunction      = isFunction;
@@ -80,7 +81,7 @@
      * Get the base node for this access
      * @return the base node
      */
-    public Node getBase() {
+    public Expression getBase() {
         return base;
     }
 
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java
--- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java	Mon Jul 22 17:40:26 2013 -0700
@@ -34,11 +34,11 @@
  * BinaryNode nodes represent two operand operations.
  */
 @Immutable
-public final class BinaryNode extends Node implements Assignment {
+public final class BinaryNode extends Expression implements Assignment {
     /** Left hand side argument. */
-    private final Node lhs;
+    private final Expression lhs;
 
-    private final Node rhs;
+    private final Expression rhs;
 
     /**
      * Constructor
@@ -47,13 +47,13 @@
      * @param lhs    left hand side
      * @param rhs    right hand side
      */
-    public BinaryNode(final long token, final Node lhs, final Node rhs) {
+    public BinaryNode(final long token, final Expression lhs, final Expression rhs) {
         super(token, lhs.getStart(), rhs.getFinish());
         this.lhs   = lhs;
         this.rhs   = rhs;
     }
 
-    private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) {
+    private BinaryNode(final BinaryNode binaryNode, final Expression lhs, final Expression rhs) {
         super(binaryNode);
         this.lhs = lhs;
         this.rhs = rhs;
@@ -141,17 +141,17 @@
     }
 
     @Override
-    public Node getAssignmentDest() {
+    public Expression getAssignmentDest() {
         return isAssignment() ? lhs() : null;
     }
 
     @Override
-    public Node setAssignmentDest(Node n) {
+    public BinaryNode setAssignmentDest(Expression n) {
         return setLHS(n);
     }
 
     @Override
-    public Node getAssignmentSource() {
+    public Expression getAssignmentSource() {
         return rhs();
     }
 
@@ -162,7 +162,7 @@
     @Override
     public Node accept(final NodeVisitor visitor) {
         if (visitor.enterBinaryNode(this)) {
-            return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor)));
+            return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor)));
         }
 
         return this;
@@ -218,7 +218,7 @@
      * Get the left hand side expression for this node
      * @return the left hand side expression
      */
-    public Node lhs() {
+    public Expression lhs() {
         return lhs;
     }
 
@@ -226,7 +226,7 @@
      * Get the right hand side expression for this node
      * @return the left hand side expression
      */
-    public Node rhs() {
+    public Expression rhs() {
         return rhs;
     }
 
@@ -235,7 +235,7 @@
      * @param lhs new left hand side expression
      * @return a node equivalent to this one except for the requested change.
      */
-    public BinaryNode setLHS(final Node lhs) {
+    public BinaryNode setLHS(final Expression lhs) {
         if (this.lhs == lhs) {
             return this;
         }
@@ -247,7 +247,7 @@
      * @param rhs new left hand side expression
      * @return a node equivalent to this one except for the requested change.
      */
-    public BinaryNode setRHS(final Node rhs) {
+    public BinaryNode setRHS(final Expression rhs) {
         if (this.rhs == rhs) {
             return this;
         }
diff -r d0545441225e -r 12baff1ad7a0 nashorn/src/jdk/nashorn/internal/ir/Block.java
--- a/nashorn/src/jdk/nashorn/internal/ir/Block.java	Thu Jul 18 03:39:39 2013 -0700
+++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java	Mon Jul 22 17:40:26 2013 -0700
@@ -38,11 +38,10 @@
 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 
 /**
- * IR representation for a list of statements and functions. All provides the
- * basis for script body.
+ * IR representation for a list of statements.
  */
 @Immutable
-public class Block extends BreakableNode implements Flags {
+public class Block extends Node implements BreakableNode, Flags {
     /** List of statements */
     protected final List statements;
 
@@ -52,6 +51,9 @@
     /** Entry label. */
     protected final Label entryLabel;
 
+    /** Break label. */
+    private final Label breakLabel;
+
     /** Does the block/function need a new scope? */
     protected final int flags;
 
@@ -76,17 +78,17 @@
     /**
      * Constructor
      *
-     * @param lineNumber line number
      * @param token      token
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final int lineNumber, final long token, final int finish, final Statement... statements) {
-        super(lineNumber, token, finish, new Label("block_break"));
+    public Block(final long token, final int finish, final Statement... statements) {
+        super(token, finish);
 
         this.statements = Arrays.asList(statements);
         this.symbols    = new LinkedHashMap<>();
         this.entryLabel = new Label("block_entry");
+        this.breakLabel = new Label("block_break");
         this.flags     =  0;
     }
 
@@ -98,8 +100,8 @@
      * @param finish     finish
      * @param statements statements
      */
-    public Block(final int lineNumber, final long token, final int finish, final List statements) {
-        this(lineNumber, token, finish, statements.toArray(new Statement[statements.size()]));
+    public Block(final long token, final int finish, final List statements) {
+        this(token, finish, statements.toArray(new Statement[statements.size()]));
     }
 
     private Block(final Block block, final int finish, final List statements, final int flags, final Map symbols) {
@@ -108,6 +110,7 @@
         this.flags      = flags;
         this.symbols    = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now
         this.entryLabel = new Label(block.entryLabel);
+        this.breakLabel = new Label(block.breakLabel);
         this.finish     = finish;
     }
 
@@ -223,6 +226,11 @@
         return entryLabel;
     }
 
+    @Override
+    public Label getBreakLabel() {
+        return breakLabel;
+    }
+
     /**
      * Get the list of statements in this block
      *
@@ -322,7 +330,17 @@
     }
 
     @Override
-    protected boolean isBreakableWithoutLabel() {
+    public boolean isBreakableWithoutLabel() {
         return false;
     }
+
+    @Override
+    public List