8067215: Disable dual fields when not using optimistic types

Fri, 10 Apr 2015 14:18:31 +0200

author
hannesw
date
Fri, 10 Apr 2015 14:18:31 +0200
changeset 1330
d82b07c9c6e3
parent 1329
63fe48ca8630
child 1331
d03eb34e4b84

8067215: Disable dual fields when not using optimistic types
Reviewed-by: attila, lagergren

buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java file | annotate | diff | comparison | revisions
docs/DEVELOPER_README file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompilerConstants.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FieldObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FindScopeDepths.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MapCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MapTuple.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/ObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/SpillObjectCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/Global.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/objects/NativeJSAdapter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/JSONParser.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/AccessorProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/AllocationStrategy.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/JSONFunctions.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/JSType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Property.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/PropertyMap.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/SetMethodCreator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/SpillProperty.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/StructureLoader.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/Bootstrap.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/NashornGuards.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/scripts/JD.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/scripts/JO.java file | annotate | diff | comparison | revisions
test/script/nosecurity/JDK-8067215.js file | annotate | diff | comparison | revisions
     1.1 --- a/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java	Thu Apr 16 17:31:32 2015 +0200
     1.2 +++ b/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java	Fri Apr 10 14:18:31 2015 +0200
     1.3 @@ -124,8 +124,6 @@
     1.4          if (memberCount > 0) {
     1.5              // call "super(map$)"
     1.6              mi.getStatic(className, PROPERTYMAP_FIELD_NAME, PROPERTYMAP_DESC);
     1.7 -            // make sure we use duplicated PropertyMap so that original map
     1.8 -            // stays intact and so can be used for many global.
     1.9              mi.invokeSpecial(PROTOTYPEOBJECT_TYPE, INIT, SCRIPTOBJECT_INIT_DESC);
    1.10              // initialize Function type fields
    1.11              initFunctionFields(mi);
     2.1 --- a/docs/DEVELOPER_README	Thu Apr 16 17:31:32 2015 +0200
     2.2 +++ b/docs/DEVELOPER_README	Fri Apr 10 14:18:31 2015 +0200
     2.3 @@ -63,16 +63,19 @@
     2.4  See the description of the codegen logger below.
     2.5  
     2.6  
     2.7 -SYSTEM PROPERTY: -Dnashorn.fields.objects
     2.8 +SYSTEM PROPERTY: -Dnashorn.fields.objects, -Dnashorn.fields.dual
     2.9  
    2.10 -When this property is true, Nashorn will only use object fields for
    2.11 -AccessorProperties. This means that primitive values must be boxed
    2.12 -when stored in a field, which is significantly slower than using
    2.13 -primitive fields.
    2.14 +When the nashorn.fields.objects property is true, Nashorn will always
    2.15 +use object fields for AccessorProperties, requiring boxing for all
    2.16 +primitive property values. When nashorn.fields.dual is set, Nashorn
    2.17 +will always use dual long/object fields, which allows primitives to be
    2.18 +stored without boxing. When neither system property is set, Nashorn
    2.19 +chooses a setting depending on the optimistic types setting (dual
    2.20 +fields when optimistic types are enabled, object-only fields otherwise).
    2.21  
    2.22 -By default, Nashorn uses dual object and long fields. Ints are
    2.23 -represented as the 32 low bits of the long fields. Doubles are
    2.24 -represented as the doubleToLongBits of their value. This way a
    2.25 +With dual fields, Nashorn uses long fields to store primitive values.
    2.26 +Ints are represented as the 32 low bits of the long fields. Doubles
    2.27 +are represented as the doubleToLongBits of their value. This way a
    2.28  single field can be used for all primitive types. Packing and
    2.29  unpacking doubles to their bit representation is intrinsified by
    2.30  the JVM and extremely fast.
     3.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Apr 16 17:31:32 2015 +0200
     3.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Apr 10 14:18:31 2015 +0200
     3.3 @@ -43,7 +43,6 @@
     3.4  import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
     3.5  import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
     3.6  import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
     3.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
     3.8  import static jdk.nashorn.internal.ir.Symbol.HAS_SLOT;
     3.9  import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
    3.10  import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
    3.11 @@ -320,6 +319,14 @@
    3.12      }
    3.13  
    3.14      /**
    3.15 +     * Are we using dual primitive/object field representation?
    3.16 +     * @return true if using dual field representation, false for object-only fields
    3.17 +     */
    3.18 +    boolean useDualFields() {
    3.19 +        return compiler.getContext().useDualFields();
    3.20 +    }
    3.21 +
    3.22 +    /**
    3.23       * Load an identity node
    3.24       *
    3.25       * @param identNode an identity node to load
    3.26 @@ -1909,10 +1916,10 @@
    3.27                          //this symbol will be put fielded, we can't initialize it as undefined with a known type
    3.28                          @Override
    3.29                          public Class<?> getValueType() {
    3.30 -                            if (OBJECT_FIELDS_ONLY || value == null || paramType == null) {
    3.31 +                            if (!useDualFields() ||  value == null || paramType == null || paramType.isBoolean()) {
    3.32                                  return Object.class;
    3.33                              }
    3.34 -                            return paramType.isBoolean() ? Object.class : paramType.getTypeClass();
    3.35 +                            return paramType.getTypeClass();
    3.36                          }
    3.37                      });
    3.38                  }
    3.39 @@ -2568,7 +2575,7 @@
    3.40  
    3.41              //for literals, a value of null means object type, i.e. the value null or getter setter function
    3.42              //(I think)
    3.43 -            final Class<?> valueType = (OBJECT_FIELDS_ONLY || value == null || value.getType().isBoolean()) ? Object.class : value.getType().getTypeClass();
    3.44 +            final Class<?> valueType = (!useDualFields() || value == null || value.getType().isBoolean()) ? Object.class : value.getType().getTypeClass();
    3.45              tuples.add(new MapTuple<Expression>(key, symbol, Type.typeFor(valueType), value) {
    3.46                  @Override
    3.47                  public Class<?> getValueType() {
     4.1 --- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Thu Apr 16 17:31:32 2015 +0200
     4.2 +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java	Fri Apr 10 14:18:31 2015 +0200
     4.3 @@ -149,8 +149,11 @@
     4.4      /** Arguments parameter in scope object constructors; in slot 3 when present */
     4.5      INIT_ARGUMENTS(null, 3),
     4.6  
     4.7 -    /** prefix for all ScriptObject subclasses with fields, @see ObjectGenerator */
     4.8 -    JS_OBJECT_PREFIX("JO"),
     4.9 +    /** prefix for all ScriptObject subclasses with dual object/primitive fields, see {@link ObjectClassGenerator} */
    4.10 +    JS_OBJECT_DUAL_FIELD_PREFIX("JD"),
    4.11 +
    4.12 +    /** prefix for all ScriptObject subclasses with object fields only, see {@link ObjectClassGenerator} */
    4.13 +    JS_OBJECT_SINGLE_FIELD_PREFIX("JO"),
    4.14  
    4.15      /** name for allocate method in JO objects */
    4.16      ALLOCATE("allocate"),
     5.1 --- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Thu Apr 16 17:31:32 2015 +0200
     5.2 +++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java	Fri Apr 10 14:18:31 2015 +0200
     5.3 @@ -151,7 +151,7 @@
     5.4      @Override
     5.5      protected PropertyMap makeMap() {
     5.6          assert propertyMap == null : "property map already initialized";
     5.7 -        propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), fieldCount, paddedFieldCount, evalCode);
     5.8 +        propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), codegen.useDualFields(), fieldCount, paddedFieldCount, evalCode);
     5.9          return propertyMap;
    5.10      }
    5.11  
    5.12 @@ -166,7 +166,7 @@
    5.13      private void putField(final MethodEmitter method, final String key, final int fieldIndex, final MapTuple<T> tuple) {
    5.14          method.dup();
    5.15  
    5.16 -        final Type    fieldType   = tuple.isPrimitive() ? PRIMITIVE_FIELD_TYPE : Type.OBJECT;
    5.17 +        final Type    fieldType   = codegen.useDualFields() && tuple.isPrimitive() ? PRIMITIVE_FIELD_TYPE : Type.OBJECT;
    5.18          final String  fieldClass  = getClassName();
    5.19          final String  fieldName   = getFieldName(fieldIndex, fieldType);
    5.20          final String  fieldDesc   = typeDescriptor(fieldType.getTypeClass());
    5.21 @@ -202,8 +202,8 @@
    5.22       */
    5.23      private void findClass() {
    5.24          fieldObjectClassName = isScope() ?
    5.25 -                ObjectClassGenerator.getClassName(fieldCount, paramCount) :
    5.26 -                ObjectClassGenerator.getClassName(paddedFieldCount);
    5.27 +                ObjectClassGenerator.getClassName(fieldCount, paramCount, codegen.useDualFields()) :
    5.28 +                ObjectClassGenerator.getClassName(paddedFieldCount, codegen.useDualFields());
    5.29  
    5.30          try {
    5.31              this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
     6.1 --- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Apr 16 17:31:32 2015 +0200
     6.2 +++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Fri Apr 10 14:18:31 2015 +0200
     6.3 @@ -207,7 +207,7 @@
     6.4          final RecompilableScriptFunctionData data = new RecompilableScriptFunctionData(
     6.5                  newFunctionNode,
     6.6                  compiler.getCodeInstaller(),
     6.7 -                ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties()),
     6.8 +                ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties(), compiler.getContext().useDualFields()),
     6.9                  nestedFunctions,
    6.10                  externalSymbolDepths.get(fnId),
    6.11                  internalSymbols.get(fnId),
     7.1 --- a/src/jdk/nashorn/internal/codegen/MapCreator.java	Thu Apr 16 17:31:32 2015 +0200
     7.2 +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java	Fri Apr 10 14:18:31 2015 +0200
     7.3 @@ -68,17 +68,17 @@
     7.4       * @param evalCode      is this property map created for 'eval' code?
     7.5       * @return New map populated with accessor properties.
     7.6       */
     7.7 -    PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum, final boolean evalCode) {
     7.8 +    PropertyMap makeFieldMap(final boolean hasArguments, final boolean dualFields, final int fieldCount, final int fieldMaximum, final boolean evalCode) {
     7.9          final List<Property> properties = new ArrayList<>();
    7.10          assert tuples != null;
    7.11  
    7.12          for (final MapTuple<T> tuple : tuples) {
    7.13              final String   key         = tuple.key;
    7.14              final Symbol   symbol      = tuple.symbol;
    7.15 -            final Class<?> initialType = tuple.getValueType();
    7.16 +            final Class<?> initialType = dualFields ? tuple.getValueType() : Object.class;
    7.17  
    7.18              if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
    7.19 -                final int      flags    = getPropertyFlags(symbol, hasArguments, evalCode);
    7.20 +                final int      flags    = getPropertyFlags(symbol, hasArguments, evalCode, dualFields);
    7.21                  final Property property = new AccessorProperty(
    7.22                          key,
    7.23                          flags,
    7.24 @@ -92,7 +92,7 @@
    7.25          return PropertyMap.newMap(properties, structure.getName(), fieldCount, fieldMaximum, 0);
    7.26      }
    7.27  
    7.28 -    PropertyMap makeSpillMap(final boolean hasArguments) {
    7.29 +    PropertyMap makeSpillMap(final boolean hasArguments, final boolean dualFields) {
    7.30          final List<Property> properties = new ArrayList<>();
    7.31          int spillIndex = 0;
    7.32          assert tuples != null;
    7.33 @@ -100,10 +100,10 @@
    7.34          for (final MapTuple<T> tuple : tuples) {
    7.35              final String key    = tuple.key;
    7.36              final Symbol symbol = tuple.symbol;
    7.37 -            final Class<?> initialType = tuple.getValueType();
    7.38 +            final Class<?> initialType = dualFields ? tuple.getValueType() : Object.class;
    7.39  
    7.40              if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
    7.41 -                final int flags = getPropertyFlags(symbol, hasArguments, false);
    7.42 +                final int flags = getPropertyFlags(symbol, hasArguments, false, dualFields);
    7.43                  properties.add(
    7.44                          new SpillProperty(
    7.45                                  key,
    7.46 @@ -124,7 +124,7 @@
    7.47       *
    7.48       * @return flags to use for fields
    7.49       */
    7.50 -    static int getPropertyFlags(final Symbol symbol, final boolean hasArguments, final boolean evalCode) {
    7.51 +    static int getPropertyFlags(final Symbol symbol, final boolean hasArguments, final boolean evalCode, final boolean dualFields) {
    7.52          int flags = 0;
    7.53  
    7.54          if (symbol.isParam()) {
    7.55 @@ -162,6 +162,10 @@
    7.56              flags |= Property.NEEDS_DECLARATION;
    7.57          }
    7.58  
    7.59 +        if (dualFields) {
    7.60 +            flags |= Property.DUAL_FIELDS;
    7.61 +        }
    7.62 +
    7.63          return flags;
    7.64      }
    7.65  }
     8.1 --- a/src/jdk/nashorn/internal/codegen/MapTuple.java	Thu Apr 16 17:31:32 2015 +0200
     8.2 +++ b/src/jdk/nashorn/internal/codegen/MapTuple.java	Fri Apr 10 14:18:31 2015 +0200
     8.3 @@ -25,8 +25,6 @@
     8.4  
     8.5  package jdk.nashorn.internal.codegen;
     8.6  
     8.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
     8.8 -
     8.9  import jdk.nashorn.internal.codegen.types.Type;
    8.10  import jdk.nashorn.internal.ir.Symbol;
    8.11  
    8.12 @@ -52,11 +50,11 @@
    8.13      }
    8.14  
    8.15      public Class<?> getValueType() {
    8.16 -        return OBJECT_FIELDS_ONLY ? Object.class : null; //until proven otherwise we are undefined, see NASHORN-592 int.class;
    8.17 +        return null; //until proven otherwise we are undefined, see NASHORN-592 int.class;
    8.18      }
    8.19  
    8.20      boolean isPrimitive() {
    8.21 -        return !OBJECT_FIELDS_ONLY && getValueType().isPrimitive() && getValueType() != boolean.class;
    8.22 +        return getValueType() != null && getValueType().isPrimitive() && getValueType() != boolean.class;
    8.23      }
    8.24  
    8.25      @Override
     9.1 --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Apr 16 17:31:32 2015 +0200
     9.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Fri Apr 10 14:18:31 2015 +0200
     9.3 @@ -31,7 +31,8 @@
     9.4  import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_MAP;
     9.5  import static jdk.nashorn.internal.codegen.CompilerConstants.INIT_SCOPE;
     9.6  import static jdk.nashorn.internal.codegen.CompilerConstants.JAVA_THIS;
     9.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX;
     9.8 +import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_DUAL_FIELD_PREFIX;
     9.9 +import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_SINGLE_FIELD_PREFIX;
    9.10  import static jdk.nashorn.internal.codegen.CompilerConstants.className;
    9.11  import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
    9.12  import static jdk.nashorn.internal.lookup.Lookup.MH;
    9.13 @@ -99,18 +100,10 @@
    9.14       */
    9.15      private final DebugLogger log;
    9.16  
    9.17 -    /**
    9.18 -     * Should the runtime only use java.lang.Object slots for fields? If this is false, the representation
    9.19 -     * will be a primitive 64-bit long value used for all primitives and a java.lang.Object for references.
    9.20 -     * This introduces a larger number of method handles in the system, as we need to have different getters
    9.21 -     * and setters for the different fields.
    9.22 -     *
    9.23 -     * This is engineered to plug into the TaggedArray implementation, when it's done.
    9.24 -     */
    9.25 -    public static final boolean OBJECT_FIELDS_ONLY = Options.getBooleanProperty("nashorn.fields.objects");
    9.26 -
    9.27 -    /** The field types in the system */
    9.28 -    private static final List<Type> FIELD_TYPES = new LinkedList<>();
    9.29 +    /** Field types for object-only fields */
    9.30 +    private static final Type[] FIELD_TYPES_OBJECT = new Type[] { Type.OBJECT };
    9.31 +    /** Field types for dual primitive/object fields */
    9.32 +    private static final Type[] FIELD_TYPES_DUAL   = new Type[] { Type.LONG, Type.OBJECT };
    9.33  
    9.34      /** What type is the primitive type in dual representation */
    9.35      public static final Type PRIMITIVE_FIELD_TYPE = Type.LONG;
    9.36 @@ -118,33 +111,27 @@
    9.37      private static final MethodHandle GET_DIFFERENT           = findOwnMH("getDifferent", Object.class, Object.class, Class.class, MethodHandle.class, MethodHandle.class, int.class);
    9.38      private static final MethodHandle GET_DIFFERENT_UNDEFINED = findOwnMH("getDifferentUndefined", Object.class, int.class);
    9.39  
    9.40 -    /**
    9.41 -     * The list of field types that we support - one type creates one field. This is currently either
    9.42 -     * LONG + OBJECT or just OBJECT for classic mode.
    9.43 -     */
    9.44 -    static {
    9.45 -        if (!OBJECT_FIELDS_ONLY) {
    9.46 -            FIELD_TYPES.add(PRIMITIVE_FIELD_TYPE);
    9.47 -        }
    9.48 -        FIELD_TYPES.add(Type.OBJECT);
    9.49 -    }
    9.50      private static boolean initialized = false;
    9.51  
    9.52      /** The context */
    9.53      private final Context context;
    9.54  
    9.55 +    private final boolean dualFields;
    9.56 +
    9.57      /**
    9.58       * Constructor
    9.59       *
    9.60       * @param context a context
    9.61 +     * @param dualFields whether to use dual fields representation
    9.62       */
    9.63 -    public ObjectClassGenerator(final Context context) {
    9.64 +    public ObjectClassGenerator(final Context context, final boolean dualFields) {
    9.65          this.context = context;
    9.66 +        this.dualFields = dualFields;
    9.67          assert context != null;
    9.68          this.log = initLogger(context);
    9.69          if (!initialized) {
    9.70              initialized = true;
    9.71 -            if (OBJECT_FIELDS_ONLY) {
    9.72 +            if (!dualFields) {
    9.73                  log.warning("Running with object fields only - this is a deprecated configuration.");
    9.74              }
    9.75          }
    9.76 @@ -176,16 +163,30 @@
    9.77          throw new AssertionError("cannot pack" + n);
    9.78      }
    9.79  
    9.80 +    private static String getPrefixName(final boolean dualFields) {
    9.81 +        return dualFields ? JS_OBJECT_DUAL_FIELD_PREFIX.symbolName() : JS_OBJECT_SINGLE_FIELD_PREFIX.symbolName();
    9.82 +    }
    9.83 +
    9.84 +    private static String getPrefixName(final String className) {
    9.85 +        if (className.startsWith(JS_OBJECT_DUAL_FIELD_PREFIX.symbolName())) {
    9.86 +            return getPrefixName(true);
    9.87 +        } else if (className.startsWith(JS_OBJECT_SINGLE_FIELD_PREFIX.symbolName())) {
    9.88 +            return getPrefixName(false);
    9.89 +        }
    9.90 +        throw new AssertionError("Not a structure class: " + className);
    9.91 +    }
    9.92 +
    9.93      /**
    9.94       * Returns the class name for JavaScript objects with fieldCount fields.
    9.95       *
    9.96       * @param fieldCount Number of fields to allocate.
    9.97 -     *
    9.98 +     * @param dualFields whether to use dual fields representation
    9.99       * @return The class name.
   9.100       */
   9.101 -    public static String getClassName(final int fieldCount) {
   9.102 -        return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount :
   9.103 -                                 SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName();
   9.104 +    public static String getClassName(final int fieldCount, final boolean dualFields) {
   9.105 +        final String prefix = getPrefixName(dualFields);
   9.106 +        return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + prefix + fieldCount :
   9.107 +                                 SCRIPTS_PACKAGE + '/' + prefix;
   9.108      }
   9.109  
   9.110      /**
   9.111 @@ -194,22 +195,23 @@
   9.112       *
   9.113       * @param fieldCount Number of fields to allocate.
   9.114       * @param paramCount Number of parameters to allocate
   9.115 -     *
   9.116 +     * @param dualFields whether to use dual fields representation
   9.117       * @return The class name.
   9.118       */
   9.119 -    public static String getClassName(final int fieldCount, final int paramCount) {
   9.120 -        return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount + SCOPE_MARKER + paramCount;
   9.121 +    public static String getClassName(final int fieldCount, final int paramCount, final boolean dualFields) {
   9.122 +        return SCRIPTS_PACKAGE + '/' + getPrefixName(dualFields) + fieldCount + SCOPE_MARKER + paramCount;
   9.123      }
   9.124  
   9.125      /**
   9.126       * Returns the number of fields in the JavaScript scope class. Its name had to be generated using either
   9.127 -     * {@link #getClassName(int)} or {@link #getClassName(int, int)}.
   9.128 +     * {@link #getClassName(int, boolean)} or {@link #getClassName(int, int, boolean)}.
   9.129       * @param clazz the JavaScript scope class.
   9.130       * @return the number of fields in the scope class.
   9.131       */
   9.132      public static int getFieldCount(final Class<?> clazz) {
   9.133          final String name = clazz.getSimpleName();
   9.134 -        final String prefix = JS_OBJECT_PREFIX.symbolName();
   9.135 +        final String prefix = getPrefixName(name);
   9.136 +
   9.137          if (prefix.equals(name)) {
   9.138              return 0;
   9.139          }
   9.140 @@ -238,8 +240,8 @@
   9.141       * @param className  name of class
   9.142       * @param fieldNames fields to initialize to undefined, where applicable
   9.143       */
   9.144 -    private static void initializeToUndefined(final MethodEmitter init, final String className, final List<String> fieldNames) {
   9.145 -        if (!OBJECT_FIELDS_ONLY) {
   9.146 +    private void initializeToUndefined(final MethodEmitter init, final String className, final List<String> fieldNames) {
   9.147 +        if (dualFields) {
   9.148              // no need to initialize anything to undefined in the dual field world
   9.149              // - then we have a constant getter for undefined for any unknown type
   9.150              return;
   9.151 @@ -292,7 +294,7 @@
   9.152       * @return Byte codes for generated class.
   9.153       */
   9.154      public byte[] generate(final int fieldCount) {
   9.155 -        final String       className    = getClassName(fieldCount);
   9.156 +        final String       className    = getClassName(fieldCount, dualFields);
   9.157          final String       superName    = className(ScriptObject.class);
   9.158          final ClassEmitter classEmitter = newClassEmitter(className, superName);
   9.159  
   9.160 @@ -322,7 +324,7 @@
   9.161       * @return Byte codes for generated class.
   9.162       */
   9.163      public byte[] generate(final int fieldCount, final int paramCount) {
   9.164 -        final String       className    = getClassName(fieldCount, paramCount);
   9.165 +        final String       className    = getClassName(fieldCount, paramCount, dualFields);
   9.166          final String       superName    = className(FunctionScope.class);
   9.167          final ClassEmitter classEmitter = newClassEmitter(className, superName);
   9.168          final List<String> initFields   = addFields(classEmitter, fieldCount);
   9.169 @@ -353,11 +355,11 @@
   9.170       *
   9.171       * @return List fields that need to be initialized.
   9.172       */
   9.173 -    private static List<String> addFields(final ClassEmitter classEmitter, final int fieldCount) {
   9.174 +    private List<String> addFields(final ClassEmitter classEmitter, final int fieldCount) {
   9.175          final List<String> initFields = new LinkedList<>();
   9.176 -
   9.177 +        final Type[] fieldTypes = dualFields ? FIELD_TYPES_DUAL : FIELD_TYPES_OBJECT;
   9.178          for (int i = 0; i < fieldCount; i++) {
   9.179 -            for (final Type type : FIELD_TYPES) {
   9.180 +            for (final Type type : fieldTypes) {
   9.181                  final String fieldName = getFieldName(i, type);
   9.182                  classEmitter.field(fieldName, type.getTypeClass());
   9.183  
   9.184 @@ -533,13 +535,10 @@
   9.185      private static MethodHandle getterForType(final Class<?> forType, final MethodHandle primitiveGetter, final MethodHandle objectGetter) {
   9.186          switch (getAccessorTypeIndex(forType)) {
   9.187          case TYPE_INT_INDEX:
   9.188 -            assert !OBJECT_FIELDS_ONLY : "this can only happen with dual fields";
   9.189              return MH.explicitCastArguments(primitiveGetter, primitiveGetter.type().changeReturnType(int.class));
   9.190          case TYPE_LONG_INDEX:
   9.191 -            assert !OBJECT_FIELDS_ONLY : "this can only happen with dual fields";
   9.192              return primitiveGetter;
   9.193          case TYPE_DOUBLE_INDEX:
   9.194 -            assert !OBJECT_FIELDS_ONLY : "this can only happen with dual fields";
   9.195              return MH.filterReturnValue(primitiveGetter, UNPACK_DOUBLE);
   9.196          case TYPE_OBJECT_INDEX:
   9.197              return objectGetter;
   9.198 @@ -557,7 +556,7 @@
   9.199          final boolean isPrimitiveStorage = forType != null && forType.isPrimitive();
   9.200  
   9.201          //which is the primordial getter
   9.202 -        final MethodHandle getter = OBJECT_FIELDS_ONLY ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
   9.203 +        final MethodHandle getter = primitiveGetter == null ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
   9.204  
   9.205          if (forType == null) {
   9.206              if (isOptimistic) {
   9.207 @@ -580,8 +579,7 @@
   9.208              return MH.dropArguments(GET_UNDEFINED.get(ti), 0, Object.class);
   9.209          }
   9.210  
   9.211 -        assert forType != null;
   9.212 -        assert !OBJECT_FIELDS_ONLY || forType == Object.class : forType;
   9.213 +        assert primitiveGetter != null || forType == Object.class : forType;
   9.214  
   9.215          if (isOptimistic) {
   9.216              if (fti < ti) {
   9.217 @@ -635,8 +633,6 @@
   9.218              return tgetter;
   9.219          }
   9.220  
   9.221 -        assert !OBJECT_FIELDS_ONLY;
   9.222 -        //final MethodType pmt = primitiveGetter.type();
   9.223          assert primitiveGetter != null;
   9.224          final MethodType tgetterType = tgetter.type();
   9.225          switch (fti) {
   9.226 @@ -727,7 +723,7 @@
   9.227          final int fti = getAccessorTypeIndex(forType);
   9.228          final int ti  = getAccessorTypeIndex(type);
   9.229  
   9.230 -        if (fti == TYPE_OBJECT_INDEX || OBJECT_FIELDS_ONLY) {
   9.231 +        if (fti == TYPE_OBJECT_INDEX || primitiveSetter == null) {
   9.232              if (ti == TYPE_OBJECT_INDEX) {
   9.233                  return objectSetter;
   9.234              }
   9.235 @@ -735,8 +731,6 @@
   9.236              return MH.asType(objectSetter, objectSetter.type().changeParameterType(1, type));
   9.237          }
   9.238  
   9.239 -        assert !OBJECT_FIELDS_ONLY;
   9.240 -
   9.241          final MethodType pmt = primitiveSetter.type();
   9.242  
   9.243          switch (fti) {
   9.244 @@ -832,8 +826,8 @@
   9.245       * @param thisProperties number of properties assigned to "this"
   9.246       * @return the allocation strategy
   9.247       */
   9.248 -    static AllocationStrategy createAllocationStrategy(final int thisProperties) {
   9.249 +    static AllocationStrategy createAllocationStrategy(final int thisProperties, final boolean dualFields) {
   9.250          final int paddedFieldCount = getPaddedFieldCount(thisProperties);
   9.251 -        return new AllocationStrategy(paddedFieldCount);
   9.252 +        return new AllocationStrategy(paddedFieldCount, dualFields);
   9.253      }
   9.254  }
    10.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Thu Apr 16 17:31:32 2015 +0200
    10.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java	Fri Apr 10 14:18:31 2015 +0200
    10.3 @@ -134,7 +134,7 @@
    10.4  
    10.5      MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple, final boolean pack) {
    10.6          loadValue(tuple.value, tuple.type);
    10.7 -        if (pack && tuple.isPrimitive()) {
    10.8 +        if (pack && codegen.useDualFields() && tuple.isPrimitive()) {
    10.9              method.pack();
   10.10          } else {
   10.11              method.convert(Type.OBJECT);
    11.1 --- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Thu Apr 16 17:31:32 2015 +0200
    11.2 +++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java	Fri Apr 10 14:18:31 2015 +0200
    11.3 @@ -27,7 +27,6 @@
    11.4  
    11.5  import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
    11.6  import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
    11.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
    11.8  
    11.9  import java.util.LinkedHashSet;
   11.10  import java.util.List;
   11.11 @@ -42,6 +41,7 @@
   11.12  import jdk.nashorn.internal.runtime.ScriptRuntime;
   11.13  import jdk.nashorn.internal.runtime.arrays.ArrayData;
   11.14  import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
   11.15 +import jdk.nashorn.internal.scripts.JD;
   11.16  import jdk.nashorn.internal.scripts.JO;
   11.17  
   11.18  /**
   11.19 @@ -65,10 +65,13 @@
   11.20          assert !isScope() : "spill scope objects are not currently supported";
   11.21  
   11.22          final int          length        = tuples.size();
   11.23 -        final long[]       jpresetValues = new long[ScriptObject.spillAllocationLength(length)];
   11.24 -        final Object[]     opresetValues = new Object[ScriptObject.spillAllocationLength(length)];
   11.25 +        final boolean      dualFields    = codegen.useDualFields();
   11.26 +        final int          spillLength   = ScriptObject.spillAllocationLength(length);
   11.27 +        final long[]       jpresetValues = dualFields ? new long[spillLength] : null;
   11.28 +        final Object[]     opresetValues = new Object[spillLength];
   11.29          final Set<Integer> postsetValues = new LinkedHashSet<>();
   11.30          final int          callSiteFlags = codegen.getCallSiteFlags();
   11.31 +        final Class<?>     objectClass   = dualFields ? JD.class : JO.class;
   11.32          ArrayData          arrayData     = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY);
   11.33  
   11.34          // Compute constant property values
   11.35 @@ -88,9 +91,9 @@
   11.36                      final Property property = propertyMap.findProperty(key);
   11.37                      if (property != null) {
   11.38                          // normal property key
   11.39 -                        property.setType(JSType.unboxedFieldType(constantValue));
   11.40 +                        property.setType(dualFields ? JSType.unboxedFieldType(constantValue) : Object.class);
   11.41                          final int slot = property.getSlot();
   11.42 -                        if (!OBJECT_FIELDS_ONLY && constantValue instanceof Number) {
   11.43 +                        if (dualFields && constantValue instanceof Number) {
   11.44                              jpresetValues[slot] = ObjectClassGenerator.pack((Number)constantValue);
   11.45                          } else {
   11.46                              opresetValues[slot] = constantValue;
   11.47 @@ -130,28 +133,32 @@
   11.48          //assert postsetValues.isEmpty() : "test me " + postsetValues;
   11.49  
   11.50          // create object and invoke constructor
   11.51 -        method._new(JO.class).dup();
   11.52 +        method._new(objectClass).dup();
   11.53          codegen.loadConstant(propertyMap);
   11.54  
   11.55          //load primitive values to j spill array
   11.56 -        codegen.loadConstant(jpresetValues);
   11.57 -        for (final int i : postsetValues) {
   11.58 -            final MapTuple<Expression> tuple    = tuples.get(i);
   11.59 -            final Property                property = propertyMap.findProperty(tuple.key);
   11.60 -            if (property != null && tuple.isPrimitive()) {
   11.61 -                method.dup();
   11.62 -                method.load(property.getSlot());
   11.63 -                loadTuple(method, tuple);
   11.64 -                method.arraystore();
   11.65 +        if (dualFields) {
   11.66 +            codegen.loadConstant(jpresetValues);
   11.67 +            for (final int i : postsetValues) {
   11.68 +                final MapTuple<Expression> tuple = tuples.get(i);
   11.69 +                final Property property = propertyMap.findProperty(tuple.key);
   11.70 +                if (property != null && tuple.isPrimitive()) {
   11.71 +                    method.dup();
   11.72 +                    method.load(property.getSlot());
   11.73 +                    loadTuple(method, tuple);
   11.74 +                    method.arraystore();
   11.75 +                }
   11.76              }
   11.77 +        } else {
   11.78 +            method.loadNull();
   11.79          }
   11.80  
   11.81          //load object values to o spill array
   11.82          codegen.loadConstant(opresetValues);
   11.83          for (final int i : postsetValues) {
   11.84 -            final MapTuple<Expression> tuple    = tuples.get(i);
   11.85 -            final Property             property = propertyMap.findProperty(tuple.key);
   11.86 -            if (property != null && !tuple.isPrimitive()) {
   11.87 +            final MapTuple<Expression> tuple = tuples.get(i);
   11.88 +            final Property property = propertyMap.findProperty(tuple.key);
   11.89 +            if (property != null && (!dualFields || !tuple.isPrimitive())) {
   11.90                  method.dup();
   11.91                  method.load(property.getSlot());
   11.92                  loadTuple(method, tuple);
   11.93 @@ -160,7 +167,7 @@
   11.94          }
   11.95  
   11.96          //instantiate the script object with spill objects
   11.97 -        method.invoke(constructorNoLookup(JO.class, PropertyMap.class, long[].class, Object[].class));
   11.98 +        method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class));
   11.99  
  11.100          // Set prefix array data if any
  11.101          if (arrayData.length() > 0) {
  11.102 @@ -171,8 +178,8 @@
  11.103  
  11.104          // set postfix
  11.105          for (final int i : postsetValues) {
  11.106 -            final MapTuple<Expression> tuple    = tuples.get(i);
  11.107 -            final Property             property = propertyMap.findProperty(tuple.key);
  11.108 +            final MapTuple<Expression> tuple = tuples.get(i);
  11.109 +            final Property property = propertyMap.findProperty(tuple.key);
  11.110              if (property == null) {
  11.111                  final int index = ArrayIndex.getArrayIndex(tuple.key);
  11.112                  assert ArrayIndex.isValidArrayIndex(index);
  11.113 @@ -188,7 +195,9 @@
  11.114      @Override
  11.115      protected PropertyMap makeMap() {
  11.116          assert propertyMap == null : "property map already initialized";
  11.117 -        propertyMap = new MapCreator<>(JO.class, tuples).makeSpillMap(false);
  11.118 +        final boolean dualFields = codegen.useDualFields();
  11.119 +        final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class;
  11.120 +        propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields());
  11.121          return propertyMap;
  11.122      }
  11.123  
    12.1 --- a/src/jdk/nashorn/internal/objects/Global.java	Thu Apr 16 17:31:32 2015 +0200
    12.2 +++ b/src/jdk/nashorn/internal/objects/Global.java	Fri Apr 10 14:18:31 2015 +0200
    12.3 @@ -79,6 +79,7 @@
    12.4  import jdk.nashorn.internal.runtime.linker.InvokeByName;
    12.5  import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
    12.6  import jdk.nashorn.internal.runtime.regexp.RegExpResult;
    12.7 +import jdk.nashorn.internal.scripts.JD;
    12.8  import jdk.nashorn.internal.scripts.JO;
    12.9  import jdk.nashorn.tools.ShellFunctions;
   12.10  
   12.11 @@ -718,7 +719,7 @@
   12.12      private static final MethodHandle LOAD                 = findOwnMH_S("load",                Object.class, Object.class, Object.class);
   12.13      private static final MethodHandle LOAD_WITH_NEW_GLOBAL = findOwnMH_S("loadWithNewGlobal",   Object.class, Object.class, Object[].class);
   12.14      private static final MethodHandle EXIT                 = findOwnMH_S("exit",                Object.class, Object.class, Object.class);
   12.15 -    private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter", Object.class, Object.class);
   12.16 +    private static final MethodHandle LEXICAL_SCOPE_FILTER = findOwnMH_S("lexicalScopeFilter",  Object.class, Object.class);
   12.17  
   12.18      // initialized by nasgen
   12.19      private static PropertyMap $nasgenmap$;
   12.20 @@ -750,6 +751,11 @@
   12.21          return context;
   12.22      }
   12.23  
   12.24 +    @Override
   12.25 +    protected boolean useDualFields() {
   12.26 +        return context.useDualFields();
   12.27 +    }
   12.28 +
   12.29      // performs initialization checks for Global constructor and returns the
   12.30      // PropertyMap, if everything is fine.
   12.31      private static PropertyMap checkAndGetMap(final Context context) {
   12.32 @@ -934,7 +940,7 @@
   12.33       * @return the new ScriptObject
   12.34       */
   12.35      public ScriptObject newObject() {
   12.36 -        return new JO(getObjectPrototype(), JO.getInitialMap());
   12.37 +        return useDualFields() ? new JD(getObjectPrototype()) : new JO(getObjectPrototype());
   12.38      }
   12.39  
   12.40      /**
   12.41 @@ -2746,8 +2752,8 @@
   12.42       */
   12.43      private static class LexicalScope extends ScriptObject {
   12.44  
   12.45 -        LexicalScope(final ScriptObject proto) {
   12.46 -            super(proto, PropertyMap.newMap());
   12.47 +        LexicalScope(final Global global) {
   12.48 +            super(global, PropertyMap.newMap());
   12.49          }
   12.50  
   12.51          @Override
    13.1 --- a/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Thu Apr 16 17:31:32 2015 +0200
    13.2 +++ b/src/jdk/nashorn/internal/objects/NativeJSAdapter.java	Fri Apr 10 14:18:31 2015 +0200
    13.3 @@ -160,7 +160,7 @@
    13.4      }
    13.5  
    13.6      private static ScriptObject wrapAdaptee(final ScriptObject adaptee) {
    13.7 -        return new JO(adaptee, JO.getInitialMap());
    13.8 +        return new JO(adaptee);
    13.9      }
   13.10  
   13.11      @Override
    14.1 --- a/src/jdk/nashorn/internal/parser/JSONParser.java	Thu Apr 16 17:31:32 2015 +0200
    14.2 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java	Fri Apr 10 14:18:31 2015 +0200
    14.3 @@ -41,6 +41,7 @@
    14.4  import jdk.nashorn.internal.runtime.SpillProperty;
    14.5  import jdk.nashorn.internal.runtime.arrays.ArrayData;
    14.6  import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
    14.7 +import jdk.nashorn.internal.scripts.JD;
    14.8  import jdk.nashorn.internal.scripts.JO;
    14.9  
   14.10  import static jdk.nashorn.internal.parser.TokenType.STRING;
   14.11 @@ -54,11 +55,10 @@
   14.12  
   14.13      final private String source;
   14.14      final private Global global;
   14.15 +    final private boolean dualFields;
   14.16      final int length;
   14.17      int pos = 0;
   14.18  
   14.19 -    private static PropertyMap EMPTY_MAP = PropertyMap.newMap();
   14.20 -
   14.21      private static final int EOF = -1;
   14.22  
   14.23      private static final String TRUE  = "true";
   14.24 @@ -74,10 +74,11 @@
   14.25       * @param source  the source
   14.26       * @param global the global object
   14.27       */
   14.28 -    public JSONParser(final String source, final Global global ) {
   14.29 +    public JSONParser(final String source, final Global global, final boolean dualFields) {
   14.30          this.source = source;
   14.31          this.global = global;
   14.32          this.length = source.length();
   14.33 +        this.dualFields = dualFields;
   14.34      }
   14.35  
   14.36      /**
   14.37 @@ -180,7 +181,7 @@
   14.38      }
   14.39  
   14.40      private Object parseObject() {
   14.41 -        PropertyMap propertyMap = EMPTY_MAP;
   14.42 +        PropertyMap propertyMap = dualFields ? JD.getInitialMap() : JO.getInitialMap();
   14.43          ArrayData arrayData = ArrayData.EMPTY_ARRAY;
   14.44          final ArrayList<Object> values = new ArrayList<>();
   14.45          int state = STATE_EMPTY;
   14.46 @@ -241,36 +242,45 @@
   14.47          return newArrayData.set(index, value, false);
   14.48      }
   14.49  
   14.50 -    private static PropertyMap addObjectProperty(final PropertyMap propertyMap, final List<Object> values,
   14.51 +    private PropertyMap addObjectProperty(final PropertyMap propertyMap, final List<Object> values,
   14.52                                                   final String id, final Object value) {
   14.53          final Property oldProperty = propertyMap.findProperty(id);
   14.54          final PropertyMap newMap;
   14.55 -        final Class<?> type = ObjectClassGenerator.OBJECT_FIELDS_ONLY ? Object.class : getType(value);
   14.56 +        final Class<?> type;
   14.57 +        final int flags;
   14.58 +        if (dualFields) {
   14.59 +            type = getType(value);
   14.60 +            flags = Property.DUAL_FIELDS;
   14.61 +        } else {
   14.62 +            type = Object.class;
   14.63 +            flags = 0;
   14.64 +        }
   14.65  
   14.66          if (oldProperty != null) {
   14.67              values.set(oldProperty.getSlot(), value);
   14.68 -            newMap = propertyMap.replaceProperty(oldProperty, new SpillProperty(id, 0, oldProperty.getSlot(), type));;
   14.69 +            newMap = propertyMap.replaceProperty(oldProperty, new SpillProperty(id, flags, oldProperty.getSlot(), type));;
   14.70          } else {
   14.71              values.add(value);
   14.72 -            newMap = propertyMap.addProperty(new SpillProperty(id, 0, propertyMap.size(), type));
   14.73 +            newMap = propertyMap.addProperty(new SpillProperty(id, flags, propertyMap.size(), type));
   14.74          }
   14.75  
   14.76          return newMap;
   14.77      }
   14.78  
   14.79      private Object createObject(final PropertyMap propertyMap, final List<Object> values, final ArrayData arrayData) {
   14.80 -        final long[] primitiveSpill = new long[values.size()];
   14.81 +        final long[] primitiveSpill = dualFields ? new long[values.size()] : null;
   14.82          final Object[] objectSpill = new Object[values.size()];
   14.83  
   14.84          for (final Property property : propertyMap.getProperties()) {
   14.85 -            if (property.getType() == Object.class) {
   14.86 +            if (!dualFields || property.getType() == Object.class) {
   14.87                  objectSpill[property.getSlot()] = values.get(property.getSlot());
   14.88              } else {
   14.89                  primitiveSpill[property.getSlot()] = ObjectClassGenerator.pack((Number) values.get(property.getSlot()));
   14.90              }
   14.91          }
   14.92  
   14.93 -        final ScriptObject object = new JO(propertyMap, primitiveSpill, objectSpill);
   14.94 +        final ScriptObject object = dualFields ?
   14.95 +                new JD(propertyMap, primitiveSpill, objectSpill) : new JO(propertyMap, null, objectSpill);
   14.96          object.setInitialProto(global.getObjectPrototype());
   14.97          object.setArray(arrayData);
   14.98          return object;
    15.1 --- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Thu Apr 16 17:31:32 2015 +0200
    15.2 +++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java	Fri Apr 10 14:18:31 2015 +0200
    15.3 @@ -25,7 +25,6 @@
    15.4  
    15.5  package jdk.nashorn.internal.runtime;
    15.6  
    15.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
    15.8  import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
    15.9  import static jdk.nashorn.internal.codegen.ObjectClassGenerator.createGetter;
   15.10  import static jdk.nashorn.internal.codegen.ObjectClassGenerator.createSetter;
   15.11 @@ -98,7 +97,7 @@
   15.12                  objectSetters[i] = MH.asType(MH.setter(LOOKUP, structure, fieldName, typeClass), Lookup.SET_OBJECT_TYPE);
   15.13              }
   15.14  
   15.15 -            if (!OBJECT_FIELDS_ONLY) {
   15.16 +            if (!StructureLoader.isSingleFieldStructure(structure.getName())) {
   15.17                  for (int i = 0; i < fieldCount; i++) {
   15.18                      final String fieldNamePrimitive = getFieldName(i, PRIMITIVE_FIELD_TYPE);
   15.19                      final Class<?> typeClass = PRIMITIVE_FIELD_TYPE.getTypeClass();
   15.20 @@ -211,7 +210,7 @@
   15.21       * @param setter the property setter or null if non writable, non configurable
   15.22       */
   15.23      private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
   15.24 -        super(key, flags | IS_BUILTIN | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
   15.25 +        super(key, flags | IS_BUILTIN | DUAL_FIELDS | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
   15.26          assert !isSpill();
   15.27  
   15.28          // we don't need to prep the setters these will never be invalidated as this is a nasgen
   15.29 @@ -221,18 +220,15 @@
   15.30          final Class<?> setterType = setter == null ? null : setter.type().parameterType(1);
   15.31  
   15.32          assert setterType == null || setterType == getterType;
   15.33 -        if (OBJECT_FIELDS_ONLY) {
   15.34 +
   15.35 +        if (getterType == int.class || getterType == long.class) {
   15.36 +            primitiveGetter = MH.asType(getter, Lookup.GET_PRIMITIVE_TYPE);
   15.37 +            primitiveSetter = setter == null ? null : MH.asType(setter, Lookup.SET_PRIMITIVE_TYPE);
   15.38 +        } else if (getterType == double.class) {
   15.39 +            primitiveGetter = MH.asType(MH.filterReturnValue(getter, ObjectClassGenerator.PACK_DOUBLE), Lookup.GET_PRIMITIVE_TYPE);
   15.40 +            primitiveSetter = setter == null ? null : MH.asType(MH.filterArguments(setter, 1, ObjectClassGenerator.UNPACK_DOUBLE), Lookup.SET_PRIMITIVE_TYPE);
   15.41 +        } else {
   15.42              primitiveGetter = primitiveSetter = null;
   15.43 -        } else {
   15.44 -            if (getterType == int.class || getterType == long.class) {
   15.45 -                primitiveGetter = MH.asType(getter, Lookup.GET_PRIMITIVE_TYPE);
   15.46 -                primitiveSetter = setter == null ? null : MH.asType(setter, Lookup.SET_PRIMITIVE_TYPE);
   15.47 -            } else if (getterType == double.class) {
   15.48 -                primitiveGetter = MH.asType(MH.filterReturnValue(getter, ObjectClassGenerator.PACK_DOUBLE), Lookup.GET_PRIMITIVE_TYPE);
   15.49 -                primitiveSetter = setter == null ? null : MH.asType(MH.filterArguments(setter, 1, ObjectClassGenerator.UNPACK_DOUBLE), Lookup.SET_PRIMITIVE_TYPE);
   15.50 -            } else {
   15.51 -                primitiveGetter = primitiveSetter = null;
   15.52 -            }
   15.53          }
   15.54  
   15.55          assert primitiveGetter == null || primitiveGetter.type() == Lookup.GET_PRIMITIVE_TYPE : primitiveGetter + "!=" + Lookup.GET_PRIMITIVE_TYPE;
   15.56 @@ -241,7 +237,7 @@
   15.57          objectGetter  = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter;
   15.58          objectSetter  = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter;
   15.59  
   15.60 -        setType(OBJECT_FIELDS_ONLY ? Object.class : getterType);
   15.61 +        setType(getterType);
   15.62      }
   15.63  
   15.64      /**
   15.65 @@ -282,6 +278,9 @@
   15.66              objectSetter    = gs.objectSetters[slot];
   15.67              primitiveSetter = gs.primitiveSetters[slot];
   15.68          }
   15.69 +
   15.70 +        // Always use dual fields except for single field structures
   15.71 +        assert hasDualFields() != StructureLoader.isSingleFieldStructure(structure.getName());
   15.72      }
   15.73  
   15.74      /**
   15.75 @@ -310,7 +309,7 @@
   15.76       */
   15.77      public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
   15.78          this(key, flags, structure, slot);
   15.79 -        setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
   15.80 +        setType(hasDualFields() ? initialType : Object.class);
   15.81      }
   15.82  
   15.83      /**
   15.84 @@ -347,7 +346,7 @@
   15.85       * @param initialValue initial value
   15.86       */
   15.87      protected final void setInitialValue(final ScriptObject owner, final Object initialValue) {
   15.88 -        setType(JSType.unboxedFieldType(initialValue));
   15.89 +        setType(hasDualFields() ? JSType.unboxedFieldType(initialValue) : Object.class);
   15.90          if (initialValue instanceof Integer) {
   15.91              invokeSetter(owner, ((Integer)initialValue).intValue());
   15.92          } else if (initialValue instanceof Long) {
   15.93 @@ -363,7 +362,7 @@
   15.94       * Initialize the type of a property
   15.95       */
   15.96      protected final void initializeType() {
   15.97 -        setType(OBJECT_FIELDS_ONLY ? Object.class : null);
   15.98 +        setType(!hasDualFields() ? Object.class : null);
   15.99      }
  15.100  
  15.101      private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
  15.102 @@ -670,7 +669,7 @@
  15.103  
  15.104      @Override
  15.105      public final boolean canChangeType() {
  15.106 -        if (OBJECT_FIELDS_ONLY) {
  15.107 +        if (!hasDualFields()) {
  15.108              return false;
  15.109          }
  15.110          // Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST.
    16.1 --- a/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Thu Apr 16 17:31:32 2015 +0200
    16.2 +++ b/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Fri Apr 10 14:18:31 2015 +0200
    16.3 @@ -44,6 +44,9 @@
    16.4      /** Number of fields in the allocated object */
    16.5      private final int fieldCount;
    16.6  
    16.7 +    /** Whether to use dual field representation */
    16.8 +    private final boolean dualFields;
    16.9 +
   16.10      /** Name of class where allocator function resides */
   16.11      private transient String allocatorClassName;
   16.12  
   16.13 @@ -53,15 +56,17 @@
   16.14      /**
   16.15       * Construct an allocation strategy with the given map and class name.
   16.16       * @param fieldCount number of fields in the allocated object
   16.17 +     * @param dualFields whether to use dual field representation
   16.18       */
   16.19 -    public AllocationStrategy(final int fieldCount) {
   16.20 +    public AllocationStrategy(final int fieldCount, final boolean dualFields) {
   16.21          this.fieldCount = fieldCount;
   16.22 +        this.dualFields = dualFields;
   16.23      }
   16.24  
   16.25      private String getAllocatorClassName() {
   16.26          if (allocatorClassName == null) {
   16.27              // These classes get loaded, so an interned variant of their name is most likely around anyway.
   16.28 -            allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount)).intern();
   16.29 +            allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount, dualFields)).intern();
   16.30          }
   16.31          return allocatorClassName;
   16.32      }
    17.1 --- a/src/jdk/nashorn/internal/runtime/Context.java	Thu Apr 16 17:31:32 2015 +0200
    17.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java	Fri Apr 10 14:18:31 2015 +0200
    17.3 @@ -131,6 +131,23 @@
    17.4      private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
    17.5  
    17.6      /**
    17.7 +     * Should scripts use only object slots for fields, or dual long/object slots? The default
    17.8 +     * behaviour is to couple this to optimistic types, using dual representation if optimistic types are enabled
    17.9 +     * and single field representation otherwise. This can be overridden by setting either the "nashorn.fields.objects"
   17.10 +     * or "nashorn.fields.dual" system property.
   17.11 +     */
   17.12 +    private final FieldMode fieldMode;
   17.13 +
   17.14 +    private static enum FieldMode {
   17.15 +        /** Value for automatic field representation depending on optimistic types setting */
   17.16 +        AUTO,
   17.17 +        /** Value for object field representation regardless of optimistic types setting */
   17.18 +        OBJECTS,
   17.19 +        /** Value for dual primitive/object field representation regardless of optimistic types setting */
   17.20 +        DUAL
   17.21 +    }
   17.22 +
   17.23 +    /**
   17.24       * Keeps track of which builtin prototypes and properties have been relinked
   17.25       * Currently we are conservative and associate the name of a builtin class with all
   17.26       * its properties, so it's enough to invalidate a property to break all assumptions
   17.27 @@ -434,7 +451,7 @@
   17.28       * @param appLoader application class loader
   17.29       */
   17.30      public Context(final Options options, final ErrorManager errors, final ClassLoader appLoader) {
   17.31 -        this(options, errors, appLoader, (ClassFilter)null);
   17.32 +        this(options, errors, appLoader, null);
   17.33      }
   17.34  
   17.35      /**
   17.36 @@ -522,6 +539,14 @@
   17.37              getErr().println("nashorn full version " + Version.fullVersion());
   17.38          }
   17.39  
   17.40 +        if (Options.getBooleanProperty("nashorn.fields.dual")) {
   17.41 +            fieldMode = FieldMode.DUAL;
   17.42 +        } else if (Options.getBooleanProperty("nashorn.fields.objects")) {
   17.43 +            fieldMode = FieldMode.OBJECTS;
   17.44 +        } else {
   17.45 +            fieldMode = FieldMode.AUTO;
   17.46 +        }
   17.47 +
   17.48          initLoggers();
   17.49      }
   17.50  
   17.51 @@ -576,6 +601,14 @@
   17.52      }
   17.53  
   17.54      /**
   17.55 +     * Should scripts compiled by this context use dual field representation?
   17.56 +     * @return true if using dual fields, false for object-only fields
   17.57 +     */
   17.58 +    public boolean useDualFields() {
   17.59 +        return fieldMode == FieldMode.DUAL || (fieldMode == FieldMode.AUTO && env._optimistic_types);
   17.60 +    }
   17.61 +
   17.62 +    /**
   17.63       * Get the PropertyMap of the current global scope
   17.64       * @return the property map of the current global scope
   17.65       */
    18.1 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Thu Apr 16 17:31:32 2015 +0200
    18.2 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java	Fri Apr 10 14:18:31 2015 +0200
    18.3 @@ -72,7 +72,8 @@
    18.4      public static Object parse(final Object text, final Object reviver) {
    18.5          final String     str    = JSType.toString(text);
    18.6          final Global     global = Context.getGlobal();
    18.7 -        final JSONParser parser = new JSONParser(str, global);
    18.8 +        final boolean    dualFields = ((ScriptObject) global).useDualFields();
    18.9 +        final JSONParser parser = new JSONParser(str, global, dualFields);
   18.10          final Object     value;
   18.11  
   18.12          try {
    19.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java	Thu Apr 16 17:31:32 2015 +0200
    19.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java	Fri Apr 10 14:18:31 2015 +0200
    19.3 @@ -26,7 +26,6 @@
    19.4  package jdk.nashorn.internal.runtime;
    19.5  
    19.6  import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
    19.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
    19.8  import static jdk.nashorn.internal.lookup.Lookup.MH;
    19.9  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
   19.10  
   19.11 @@ -1973,10 +1972,6 @@
   19.12       * @return primive type or Object.class if not primitive
   19.13       */
   19.14      public static Class<?> unboxedFieldType(final Object o) {
   19.15 -        if (OBJECT_FIELDS_ONLY) {
   19.16 -            return Object.class;
   19.17 -        }
   19.18 -
   19.19          if (o == null) {
   19.20              return Object.class;
   19.21          } else if (o.getClass() == Integer.class) {
    20.1 --- a/src/jdk/nashorn/internal/runtime/Property.java	Thu Apr 16 17:31:32 2015 +0200
    20.2 +++ b/src/jdk/nashorn/internal/runtime/Property.java	Fri Apr 10 14:18:31 2015 +0200
    20.3 @@ -96,6 +96,9 @@
    20.4      /** Is this property an ES6 lexical binding? */
    20.5      public static final int IS_LEXICAL_BINDING      = 1 << 10;
    20.6  
    20.7 +    /** Does this property support dual field representation? */
    20.8 +    public static final int DUAL_FIELDS             = 1 << 11;
    20.9 +
   20.10      /** Property key. */
   20.11      private final String key;
   20.12  
   20.13 @@ -286,7 +289,7 @@
   20.14       * @return true if parameter
   20.15       */
   20.16      public boolean isParameter() {
   20.17 -        return (flags & IS_PARAMETER) == IS_PARAMETER;
   20.18 +        return (flags & IS_PARAMETER) != 0;
   20.19      }
   20.20  
   20.21      /**
   20.22 @@ -294,7 +297,7 @@
   20.23       * @return true if has arguments
   20.24       */
   20.25      public boolean hasArguments() {
   20.26 -        return (flags & HAS_ARGUMENTS) == HAS_ARGUMENTS;
   20.27 +        return (flags & HAS_ARGUMENTS) != 0;
   20.28      }
   20.29  
   20.30      /**
   20.31 @@ -316,7 +319,7 @@
   20.32       * @return true if this is a bound property
   20.33       */
   20.34      public boolean isBound() {
   20.35 -        return (flags & IS_BOUND) == IS_BOUND;
   20.36 +        return (flags & IS_BOUND) != 0;
   20.37      }
   20.38  
   20.39      /**
   20.40 @@ -325,7 +328,7 @@
   20.41       * @return true if this is a block-scoped variable
   20.42       */
   20.43      public boolean needsDeclaration() {
   20.44 -        return (flags & NEEDS_DECLARATION) == NEEDS_DECLARATION;
   20.45 +        return (flags & NEEDS_DECLARATION) != 0;
   20.46      }
   20.47  
   20.48      /**
   20.49 @@ -346,16 +349,6 @@
   20.50      }
   20.51  
   20.52      /**
   20.53 -     * Check if a flag is set for a property
   20.54 -     * @param property property
   20.55 -     * @param flag     flag to check
   20.56 -     * @return true if flag is set
   20.57 -     */
   20.58 -    public static boolean checkFlag(final Property property, final int flag) {
   20.59 -        return (property.getFlags() & flag) == flag;
   20.60 -    }
   20.61 -
   20.62 -    /**
   20.63       * Get the flags for this property
   20.64       * @return property flags
   20.65       */
   20.66 @@ -364,16 +357,6 @@
   20.67      }
   20.68  
   20.69      /**
   20.70 -     * Get the modify flags for this property. The modify flags are the ECMA 8.6.1
   20.71 -     * flags that decide if the Property is writable, configurable and/or enumerable.
   20.72 -     *
   20.73 -     * @return modify flags for property
   20.74 -     */
   20.75 -    public int getModifyFlags() {
   20.76 -        return flags & MODIFY_MASK;
   20.77 -    }
   20.78 -
   20.79 -    /**
   20.80       * Remove property flags from the property. Properties are immutable here,
   20.81       * so any property change that results in a smaller flag set results in the
   20.82       * property being cloned. Use only the return value
   20.83 @@ -715,7 +698,7 @@
   20.84       * @return whether this property is a function declaration or not.
   20.85       */
   20.86      public boolean isFunctionDeclaration() {
   20.87 -        return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION;
   20.88 +        return (flags & IS_FUNCTION_DECLARATION) != 0;
   20.89      }
   20.90  
   20.91      /**
   20.92 @@ -723,6 +706,14 @@
   20.93       * @return true if this property represents a lexical binding.
   20.94       */
   20.95      public boolean isLexicalBinding() {
   20.96 -        return (flags & IS_LEXICAL_BINDING) == IS_LEXICAL_BINDING;
   20.97 +        return (flags & IS_LEXICAL_BINDING) != 0;
   20.98 +    }
   20.99 +
  20.100 +    /**
  20.101 +     * Does this property support dual fields for both primitive and object values?
  20.102 +     * @return true if supports dual fields
  20.103 +     */
  20.104 +    public boolean hasDualFields() {
  20.105 +        return (flags & DUAL_FIELDS) != 0;
  20.106      }
  20.107  }
    21.1 --- a/src/jdk/nashorn/internal/runtime/PropertyMap.java	Thu Apr 16 17:31:32 2015 +0200
    21.2 +++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java	Fri Apr 10 14:18:31 2015 +0200
    21.3 @@ -199,12 +199,21 @@
    21.4      }
    21.5  
    21.6      /**
    21.7 +     * Return a sharable empty map for the given object class.
    21.8 +     * @param clazz the base object class
    21.9 +     * @return New empty {@link PropertyMap}.
   21.10 +     */
   21.11 +    public static PropertyMap newMap(final Class<? extends ScriptObject> clazz) {
   21.12 +        return new PropertyMap(EMPTY_HASHMAP, clazz.getName(), 0, 0, 0, false);
   21.13 +    }
   21.14 +
   21.15 +    /**
   21.16       * Return a sharable empty map.
   21.17       *
   21.18       * @return New empty {@link PropertyMap}.
   21.19       */
   21.20      public static PropertyMap newMap() {
   21.21 -        return new PropertyMap(EMPTY_HASHMAP, JO.class.getName(), 0, 0, 0, false);
   21.22 +        return newMap(JO.class);
   21.23      }
   21.24  
   21.25      /**
    22.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Apr 16 17:31:32 2015 +0200
    22.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Fri Apr 10 14:18:31 2015 +0200
    22.3 @@ -28,7 +28,6 @@
    22.4  import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
    22.5  import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
    22.6  import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
    22.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
    22.8  import static jdk.nashorn.internal.lookup.Lookup.MH;
    22.9  import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
   22.10  import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
   22.11 @@ -146,12 +145,6 @@
   22.12      /** Area for reference properties added to object after instantiation, see {@link AccessorProperty} */
   22.13      protected Object[] objectSpill;
   22.14  
   22.15 -    /**
   22.16 -     * Number of elements in the spill. This may be less than the spill array lengths, if not all of
   22.17 -     * the allocated memory is in use
   22.18 -     */
   22.19 -    private int spillLength;
   22.20 -
   22.21      /** Indexed array data. */
   22.22      private ArrayData arrayData;
   22.23  
   22.24 @@ -171,12 +164,6 @@
   22.25      /** Method handle for getting the array data */
   22.26      public static final Call GET_ARRAY          = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArray", ArrayData.class);
   22.27  
   22.28 -    /** Method handle for getting the property map - debugging purposes */
   22.29 -    public static final Call GET_MAP            = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getMap", PropertyMap.class);
   22.30 -
   22.31 -    /** Method handle for setting the array data */
   22.32 -    public static final Call SET_ARRAY          = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArray", void.class, ArrayData.class);
   22.33 -
   22.34      /** Method handle for getting a function argument at a given index. Used from MapCreator */
   22.35      public static final Call GET_ARGUMENT       = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class);
   22.36  
   22.37 @@ -259,8 +246,7 @@
   22.38          this(map);
   22.39          this.primitiveSpill = primitiveSpill;
   22.40          this.objectSpill    = objectSpill;
   22.41 -        assert primitiveSpill.length == objectSpill.length : " primitive spill pool size is not the same length as object spill pool size";
   22.42 -        this.spillLength = spillAllocationLength(primitiveSpill.length);
   22.43 +        assert primitiveSpill == null || primitiveSpill.length == objectSpill.length : " primitive spill pool size is not the same length as object spill pool size";
   22.44      }
   22.45  
   22.46      /**
   22.47 @@ -727,7 +713,7 @@
   22.48              setArray(getArray().ensure(longIndex));
   22.49              doesNotHaveEnsureDelete(longIndex, oldLength, false);
   22.50          }
   22.51 -        setArray(getArray().set(index,value, false));
   22.52 +        setArray(getArray().set(index, value, false));
   22.53      }
   22.54  
   22.55      private void checkIntegerKey(final String key) {
   22.56 @@ -976,10 +962,10 @@
   22.57       * @param setter        setter for {@link UserAccessorProperty}, null if not present or N/A
   22.58       */
   22.59      protected final void initUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
   22.60 -        final int slot = spillLength;
   22.61 -        ensureSpillSize(spillLength); //arguments=slot0, caller=slot0
   22.62 +        final PropertyMap oldMap = getMap();
   22.63 +        final int slot = oldMap.getFreeSpillSlot();
   22.64 +        ensureSpillSize(slot);
   22.65          objectSpill[slot] = new UserAccessorProperty.Accessors(getter, setter);
   22.66 -        final PropertyMap oldMap = getMap();
   22.67          Property    newProperty;
   22.68          PropertyMap newMap;
   22.69          do {
   22.70 @@ -1006,19 +992,12 @@
   22.71              final int slot = uc.getSlot();
   22.72  
   22.73              assert uc.getLocalType() == Object.class;
   22.74 -            if (slot >= spillLength) {
   22.75 -                uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
   22.76 -            } else {
   22.77 -                final UserAccessorProperty.Accessors gs = uc.getAccessors(this); //this crashes
   22.78 -                if (gs == null) {
   22.79 -                    uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
   22.80 -                } else {
   22.81 -                    //reuse existing getter setter for speed
   22.82 -                    gs.set(getter, setter);
   22.83 -                    if (uc.getFlags() == propertyFlags) {
   22.84 -                        return oldProperty;
   22.85 -                    }
   22.86 -                }
   22.87 +            final UserAccessorProperty.Accessors gs = uc.getAccessors(this); //this crashes
   22.88 +            assert gs != null;
   22.89 +            //reuse existing getter setter for speed
   22.90 +            gs.set(getter, setter);
   22.91 +            if (uc.getFlags() == propertyFlags) {
   22.92 +                return oldProperty;
   22.93              }
   22.94              newProperty = new UserAccessorProperty(uc.getKey(), propertyFlags, slot);
   22.95          } else {
   22.96 @@ -2053,8 +2032,6 @@
   22.97              protoSwitchPoint = null;
   22.98          }
   22.99  
  22.100 -        assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
  22.101 -
  22.102          final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
  22.103          return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
  22.104      }
  22.105 @@ -2531,13 +2508,14 @@
  22.106  
  22.107      /**
  22.108       * Add a spill property for the given key.
  22.109 -     * @param key           Property key.
  22.110 -     * @param propertyFlags Property flags.
  22.111 +     * @param key    Property key.
  22.112 +     * @param flags  Property flags.
  22.113       * @return Added property.
  22.114       */
  22.115 -    private Property addSpillProperty(final String key, final int propertyFlags, final Object value, final boolean hasInitialValue) {
  22.116 +    private Property addSpillProperty(final String key, final int flags, final Object value, final boolean hasInitialValue) {
  22.117          final PropertyMap propertyMap = getMap();
  22.118          final int fieldSlot  = propertyMap.getFreeFieldSlot();
  22.119 +        final int propertyFlags = flags | (useDualFields() ? Property.DUAL_FIELDS : 0);
  22.120  
  22.121          Property property;
  22.122          if (fieldSlot > -1) {
  22.123 @@ -2562,7 +2540,7 @@
  22.124       * @return Setter method handle.
  22.125       */
  22.126      MethodHandle addSpill(final Class<?> type, final String key) {
  22.127 -        return addSpillProperty(key, 0, null, false).getSetter(OBJECT_FIELDS_ONLY ? Object.class : type, getMap());
  22.128 +        return addSpillProperty(key, 0, null, false).getSetter(type, getMap());
  22.129      }
  22.130  
  22.131      /**
  22.132 @@ -2649,9 +2627,9 @@
  22.133          final int spreadArgs = mh.type().parameterCount() - callSiteParamCount + 1;
  22.134          return MH.filterArguments(
  22.135              MH.asSpreader(
  22.136 -            mh,
  22.137 -            Object[].class,
  22.138 -            spreadArgs),
  22.139 +                mh,
  22.140 +                Object[].class,
  22.141 +                spreadArgs),
  22.142              callSiteParamCount - 1,
  22.143              MH.insertArguments(
  22.144                  TRUNCATINGFILTER,
  22.145 @@ -3739,24 +3717,32 @@
  22.146          return uc;
  22.147      }
  22.148  
  22.149 +    /**
  22.150 +     * Returns {@code true} if properties for this object should use dual field mode, {@code false} otherwise.
  22.151 +     * @return {@code true} if dual fields should be used.
  22.152 +     */
  22.153 +    protected boolean useDualFields() {
  22.154 +        return !StructureLoader.isSingleFieldStructure(getClass().getName());
  22.155 +    }
  22.156 +
  22.157      Object ensureSpillSize(final int slot) {
  22.158 -        if (slot < spillLength) {
  22.159 +        final int oldLength = objectSpill == null ? 0 : objectSpill.length;
  22.160 +        if (slot < oldLength) {
  22.161              return this;
  22.162          }
  22.163          final int newLength = alignUp(slot + 1, SPILL_RATE);
  22.164          final Object[] newObjectSpill    = new Object[newLength];
  22.165 -        final long[]   newPrimitiveSpill = OBJECT_FIELDS_ONLY ? null : new long[newLength];
  22.166 +        final long[]   newPrimitiveSpill = useDualFields() ? new long[newLength] : null;
  22.167  
  22.168          if (objectSpill != null) {
  22.169 -            System.arraycopy(objectSpill, 0, newObjectSpill, 0, spillLength);
  22.170 -            if (!OBJECT_FIELDS_ONLY) {
  22.171 -                System.arraycopy(primitiveSpill, 0, newPrimitiveSpill, 0, spillLength);
  22.172 +            System.arraycopy(objectSpill, 0, newObjectSpill, 0, oldLength);
  22.173 +            if (primitiveSpill != null && newPrimitiveSpill != null) {
  22.174 +                System.arraycopy(primitiveSpill, 0, newPrimitiveSpill, 0, oldLength);
  22.175              }
  22.176          }
  22.177  
  22.178          this.primitiveSpill = newPrimitiveSpill;
  22.179          this.objectSpill    = newObjectSpill;
  22.180 -        this.spillLength = newLength;
  22.181  
  22.182          return this;
  22.183      }
    23.1 --- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Thu Apr 16 17:31:32 2015 +0200
    23.2 +++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java	Fri Apr 10 14:18:31 2015 +0200
    23.3 @@ -232,14 +232,18 @@
    23.4      }
    23.5  
    23.6      private SetMethod createNewFieldSetter(final SwitchPoint builtinSwitchPoint) {
    23.7 -        return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
    23.8 +        return createNewSetter(new AccessorProperty(getName(), getFlags(sobj), sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
    23.9      }
   23.10  
   23.11      private SetMethod createNewSpillPropertySetter(final SwitchPoint builtinSwitchPoint) {
   23.12 -        return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
   23.13 +        return createNewSetter(new SpillProperty(getName(), getFlags(sobj), getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
   23.14      }
   23.15  
   23.16      private PropertyMap getNewMap(final Property property) {
   23.17          return getMap().addProperty(property);
   23.18      }
   23.19 +
   23.20 +    private static int getFlags(final ScriptObject scriptObject) {
   23.21 +        return scriptObject.useDualFields() ? Property.DUAL_FIELDS : 0;
   23.22 +    }
   23.23  }
    24.1 --- a/src/jdk/nashorn/internal/runtime/SpillProperty.java	Thu Apr 16 17:31:32 2015 +0200
    24.2 +++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java	Fri Apr 10 14:18:31 2015 +0200
    24.3 @@ -25,7 +25,6 @@
    24.4  
    24.5  package jdk.nashorn.internal.runtime;
    24.6  
    24.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
    24.8  import static jdk.nashorn.internal.lookup.Lookup.MH;
    24.9  
   24.10  import java.lang.invoke.MethodHandle;
   24.11 @@ -139,11 +138,11 @@
   24.12          }
   24.13      }
   24.14  
   24.15 -    private static MethodHandle primitiveGetter(final int slot) {
   24.16 -        return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, true);
   24.17 +    private static MethodHandle primitiveGetter(final int slot, final int flags) {
   24.18 +        return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, true) : null;
   24.19      }
   24.20 -    private static MethodHandle primitiveSetter(final int slot) {
   24.21 -        return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, false);
   24.22 +    private static MethodHandle primitiveSetter(final int slot, final int flags) {
   24.23 +        return (flags & DUAL_FIELDS) == DUAL_FIELDS ? Accessors.getCached(slot, true, false) : null;
   24.24      }
   24.25      private static MethodHandle objectGetter(final int slot) {
   24.26          return Accessors.getCached(slot, false, true);
   24.27 @@ -160,8 +159,7 @@
   24.28       * @param slot   spill slot
   24.29       */
   24.30      public SpillProperty(final String key, final int flags, final int slot) {
   24.31 -        super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
   24.32 -        assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class;
   24.33 +        super(key, flags, slot, primitiveGetter(slot, flags), primitiveSetter(slot, flags), objectGetter(slot), objectSetter(slot));
   24.34      }
   24.35  
   24.36      /**
   24.37 @@ -173,7 +171,7 @@
   24.38       */
   24.39      public SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
   24.40          this(key, flags, slot);
   24.41 -        setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
   24.42 +        setType(hasDualFields() ? initialType : Object.class);
   24.43      }
   24.44  
   24.45      SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
   24.46 @@ -216,8 +214,8 @@
   24.47      @Override
   24.48      void initMethodHandles(final Class<?> structure) {
   24.49          final int slot  = getSlot();
   24.50 -        primitiveGetter = primitiveGetter(slot);
   24.51 -        primitiveSetter = primitiveSetter(slot);
   24.52 +        primitiveGetter = primitiveGetter(slot, getFlags());
   24.53 +        primitiveSetter = primitiveSetter(slot, getFlags());
   24.54          objectGetter    = objectGetter(slot);
   24.55          objectSetter    = objectSetter(slot);
   24.56      }
    25.1 --- a/src/jdk/nashorn/internal/runtime/StructureLoader.java	Thu Apr 16 17:31:32 2015 +0200
    25.2 +++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java	Fri Apr 10 14:18:31 2015 +0200
    25.3 @@ -27,7 +27,8 @@
    25.4  
    25.5  import static jdk.nashorn.internal.codegen.Compiler.SCRIPTS_PACKAGE;
    25.6  import static jdk.nashorn.internal.codegen.Compiler.binaryName;
    25.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_PREFIX;
    25.8 +import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_DUAL_FIELD_PREFIX;
    25.9 +import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_SINGLE_FIELD_PREFIX;
   25.10  
   25.11  import java.security.ProtectionDomain;
   25.12  import jdk.nashorn.internal.codegen.ObjectClassGenerator;
   25.13 @@ -36,7 +37,8 @@
   25.14   * Responsible for on the fly construction of structure classes.
   25.15   */
   25.16  final class StructureLoader extends NashornLoader {
   25.17 -    private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.symbolName();
   25.18 +    private static final String SINGLE_FIELD_PREFIX = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_SINGLE_FIELD_PREFIX.symbolName();
   25.19 +    private static final String DUAL_FIELD_PREFIX   = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_DUAL_FIELD_PREFIX.symbolName();
   25.20  
   25.21      /**
   25.22       * Constructor.
   25.23 @@ -45,14 +47,39 @@
   25.24          super(parent);
   25.25      }
   25.26  
   25.27 +    /**
   25.28 +     * Returns true if the class name represents a structure object with dual primitive/object fields.
   25.29 +     * @param name a class name
   25.30 +     * @return true if a dual field structure class
   25.31 +     */
   25.32 +    private static boolean isDualFieldStructure(final String name) {
   25.33 +        return name.startsWith(DUAL_FIELD_PREFIX);
   25.34 +    }
   25.35 +
   25.36 +    /**
   25.37 +     * Returns true if the class name represents a structure object with single object-only fields.
   25.38 +     * @param name a class name
   25.39 +     * @return true if a single field structure class
   25.40 +     */
   25.41 +    static boolean isSingleFieldStructure(final String name) {
   25.42 +        return name.startsWith(SINGLE_FIELD_PREFIX);
   25.43 +    }
   25.44 +
   25.45 +    /**
   25.46 +     * Returns true if the class name represents a Nashorn structure object.
   25.47 +     * @param name a class name
   25.48 +     * @return true if a structure class
   25.49 +     */
   25.50      static boolean isStructureClass(final String name) {
   25.51 -        return name.startsWith(JS_OBJECT_PREFIX_EXTERNAL);
   25.52 +        return isDualFieldStructure(name) || isSingleFieldStructure(name);
   25.53      }
   25.54  
   25.55      @Override
   25.56      protected Class<?> findClass(final String name) throws ClassNotFoundException {
   25.57 -        if (isStructureClass(name)) {
   25.58 -            return generateClass(name, name.substring(JS_OBJECT_PREFIX_EXTERNAL.length()));
   25.59 +        if (isDualFieldStructure(name)) {
   25.60 +            return generateClass(name, name.substring(DUAL_FIELD_PREFIX.length()), true);
   25.61 +        } else if (isSingleFieldStructure(name)) {
   25.62 +            return generateClass(name, name.substring(SINGLE_FIELD_PREFIX.length()), false);
   25.63          }
   25.64          return super.findClass(name);
   25.65      }
   25.66 @@ -63,10 +90,10 @@
   25.67       * @param descriptor Layout descriptor.
   25.68       * @return Generated class.
   25.69       */
   25.70 -    private Class<?> generateClass(final String name, final String descriptor) {
   25.71 +    private Class<?> generateClass(final String name, final String descriptor, final boolean dualFields) {
   25.72          final Context context = Context.getContextTrusted();
   25.73  
   25.74 -        final byte[] code = new ObjectClassGenerator(context).generate(descriptor);
   25.75 +        final byte[] code = new ObjectClassGenerator(context, dualFields).generate(descriptor);
   25.76          return defineClass(name, code, 0, code.length, new ProtectionDomain(null, getPermissions(null)));
   25.77      }
   25.78  }
    26.1 --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu Apr 16 17:31:32 2015 +0200
    26.2 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Fri Apr 10 14:18:31 2015 +0200
    26.3 @@ -74,17 +74,16 @@
    26.4       * of object fields only, it is fine. However, with dual fields, in order to get
    26.5       * performance on benchmarks with a lot of object instantiation and then field
    26.6       * reassignment, it can take slightly more relinks to become stable with type
    26.7 -     * changes swapping out an entire proprety map and making a map guard fail.
    26.8 -     * Therefore the relink threshold is set to 16 for dual fields (now the default).
    26.9 -     * This doesn't seem to have any other negative performance implication.
   26.10 +     * changes swapping out an entire property map and making a map guard fail.
   26.11 +     * Since we need to set this value statically it must work with possibly changing
   26.12 +     * optimistic types and dual fields settings. A higher value does not seem to have
   26.13 +     * any other negative performance implication when running with object-only fields,
   26.14 +     * so we choose a higher value here.
   26.15       *
   26.16       * See for example octane.gbemu, run with --log=fields:warning to study
   26.17       * megamorphic behavior
   26.18       */
   26.19 -    private static final int NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD =
   26.20 -            ObjectClassGenerator.OBJECT_FIELDS_ONLY ?
   26.21 -                     8 :
   26.22 -                    16;
   26.23 +    private static final int NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD = 16;
   26.24  
   26.25      // do not create me!!
   26.26      private Bootstrap() {
    27.1 --- a/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Thu Apr 16 17:31:32 2015 +0200
    27.2 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java	Fri Apr 10 14:18:31 2015 +0200
    27.3 @@ -33,7 +33,6 @@
    27.4  import jdk.internal.dynalink.CallSiteDescriptor;
    27.5  import jdk.internal.dynalink.linker.LinkRequest;
    27.6  import jdk.nashorn.api.scripting.JSObject;
    27.7 -import jdk.nashorn.internal.codegen.ObjectClassGenerator;
    27.8  import jdk.nashorn.internal.objects.Global;
    27.9  import jdk.nashorn.internal.runtime.Property;
   27.10  import jdk.nashorn.internal.runtime.PropertyMap;
   27.11 @@ -123,7 +122,7 @@
   27.12       */
   27.13      static boolean needsGuard(final Property property, final CallSiteDescriptor desc) {
   27.14          return property == null || property.isConfigurable()
   27.15 -                || property.isBound() || !ObjectClassGenerator.OBJECT_FIELDS_ONLY
   27.16 +                || property.isBound() || property.hasDualFields()
   27.17                  || !NashornCallSiteDescriptor.isFastScope(desc) || property.canChangeType();
   27.18      }
   27.19  
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/src/jdk/nashorn/internal/scripts/JD.java	Fri Apr 10 14:18:31 2015 +0200
    28.3 @@ -0,0 +1,88 @@
    28.4 +/*
    28.5 + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
    28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    28.7 + *
    28.8 + * This code is free software; you can redistribute it and/or modify it
    28.9 + * under the terms of the GNU General Public License version 2 only, as
   28.10 + * published by the Free Software Foundation.  Oracle designates this
   28.11 + * particular file as subject to the "Classpath" exception as provided
   28.12 + * by Oracle in the LICENSE file that accompanied this code.
   28.13 + *
   28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   28.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   28.17 + * version 2 for more details (a copy is included in the LICENSE file that
   28.18 + * accompanied this code).
   28.19 + *
   28.20 + * You should have received a copy of the GNU General Public License version
   28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   28.23 + *
   28.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   28.25 + * or visit www.oracle.com if you need additional information or have any
   28.26 + * questions.
   28.27 + */
   28.28 +
   28.29 +package jdk.nashorn.internal.scripts;
   28.30 +
   28.31 +import jdk.nashorn.internal.runtime.PropertyMap;
   28.32 +import jdk.nashorn.internal.runtime.ScriptObject;
   28.33 +
   28.34 +/**
   28.35 + * Empty object class for dual primitive-object fields.
   28.36 + */
   28.37 +public class JD extends ScriptObject {
   28.38 +
   28.39 +    private static final PropertyMap map$ = PropertyMap.newMap(JD.class);
   28.40 +
   28.41 +    /**
   28.42 +     * Returns the initial property map to be used.
   28.43 +     * @return the initial property map.
   28.44 +     */
   28.45 +    public static PropertyMap getInitialMap() {
   28.46 +        return map$;
   28.47 +    }
   28.48 +
   28.49 +    /**
   28.50 +     * Constructor given an initial property map
   28.51 +     *
   28.52 +     * @param map the property map
   28.53 +     */
   28.54 +    public JD(final PropertyMap map) {
   28.55 +        super(map);
   28.56 +    }
   28.57 +
   28.58 +    /**
   28.59 +     * Constructor given an initial prototype and the default initial property map.
   28.60 +     *
   28.61 +     * @param proto the prototype object
   28.62 +     */
   28.63 +    public JD(final ScriptObject proto) {
   28.64 +        super(proto, getInitialMap());
   28.65 +    }
   28.66 +
   28.67 +    /**
   28.68 +     * Constructor that takes a pre-initialized spill pool. Used by
   28.69 +     * {@link jdk.nashorn.internal.codegen.SpillObjectCreator} and
   28.70 +     * {@link jdk.nashorn.internal.parser.JSONParser} for initializing object literals
   28.71 +     *
   28.72 +     * @param map            property map
   28.73 +     * @param primitiveSpill primitive spill pool
   28.74 +     * @param objectSpill    reference spill pool
   28.75 +     */
   28.76 +    public JD(final PropertyMap map, final long[] primitiveSpill, final Object[] objectSpill) {
   28.77 +        super(map, primitiveSpill, objectSpill);
   28.78 +    }
   28.79 +
   28.80 +    /**
   28.81 +     * A method handle of this method is passed to the ScriptFunction constructor.
   28.82 +     *
   28.83 +     * @param map  the property map to use for allocatorMap
   28.84 +     *
   28.85 +     * @return newly allocated ScriptObject
   28.86 +     */
   28.87 +    public static ScriptObject allocate(final PropertyMap map) {
   28.88 +        return new JD(map);
   28.89 +    }
   28.90 +}
   28.91 +
    29.1 --- a/src/jdk/nashorn/internal/scripts/JO.java	Thu Apr 16 17:31:32 2015 +0200
    29.2 +++ b/src/jdk/nashorn/internal/scripts/JO.java	Fri Apr 10 14:18:31 2015 +0200
    29.3 @@ -1,5 +1,5 @@
    29.4  /*
    29.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
    29.6 + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
    29.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    29.8   *
    29.9   * This code is free software; you can redistribute it and/or modify it
   29.10 @@ -29,11 +29,11 @@
   29.11  import jdk.nashorn.internal.runtime.ScriptObject;
   29.12  
   29.13  /**
   29.14 - * Empty object class.
   29.15 + * Empty object class for object-only fields.
   29.16   */
   29.17  public class JO extends ScriptObject {
   29.18  
   29.19 -    private static final PropertyMap map$ = PropertyMap.newMap();
   29.20 +    private static final PropertyMap map$ = PropertyMap.newMap(JO.class);
   29.21  
   29.22      /**
   29.23       * Returns the initial property map to be used.
   29.24 @@ -53,13 +53,12 @@
   29.25      }
   29.26  
   29.27      /**
   29.28 -     * Constructor given an initial prototype and an initial property map.
   29.29 +     * Constructor given an initial prototype and the default initial property map.
   29.30       *
   29.31       * @param proto the prototype object
   29.32 -     * @param map the property map
   29.33       */
   29.34 -    public JO(final ScriptObject proto, final PropertyMap map) {
   29.35 -        super(proto, map);
   29.36 +    public JO(final ScriptObject proto) {
   29.37 +        super(proto, getInitialMap());
   29.38      }
   29.39  
   29.40      /**
   29.41 @@ -86,3 +85,4 @@
   29.42          return new JO(map);
   29.43      }
   29.44  }
   29.45 +
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/script/nosecurity/JDK-8067215.js	Fri Apr 10 14:18:31 2015 +0200
    30.3 @@ -0,0 +1,104 @@
    30.4 +/*
    30.5 + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
    30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    30.7 + * 
    30.8 + * This code is free software; you can redistribute it and/or modify it
    30.9 + * under the terms of the GNU General Public License version 2 only, as
   30.10 + * published by the Free Software Foundation.
   30.11 + * 
   30.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   30.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   30.15 + * version 2 for more details (a copy is included in the LICENSE file that
   30.16 + * accompanied this code).
   30.17 + * 
   30.18 + * You should have received a copy of the GNU General Public License version
   30.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   30.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   30.21 + * 
   30.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   30.23 + * or visit www.oracle.com if you need additional information or have any
   30.24 + * questions.
   30.25 + */
   30.26 +
   30.27 +/**
   30.28 + * JDK-8067215: Disable dual fields when not using optimistic types
   30.29 + *
   30.30 + * @test
   30.31 + * @run
   30.32 + * @option -Dnashorn.debug=true
   30.33 + * @fork
   30.34 + */
   30.35 +
   30.36 +var intType    = Java.type("int");
   30.37 +var doubleType = Java.type("double");
   30.38 +var longType   = Java.type("long");
   30.39 +var objectType = Java.type("java.lang.Object");
   30.40 +
   30.41 +var Context = Java.type("jdk.nashorn.internal.runtime.Context");
   30.42 +var JSType  = Java.type("jdk.nashorn.internal.runtime.JSType");
   30.43 +
   30.44 +var context = Context.getContext();
   30.45 +var dualFields = context.useDualFields();
   30.46 +var optimisticTypes = context.getEnv()._optimistic_types;
   30.47 +
   30.48 +if (dualFields != optimisticTypes) {
   30.49 +    throw new Error("Wrong dual fields setting");
   30.50 +}
   30.51 +
   30.52 +function testMap(obj) {
   30.53 +    obj.x = "foo";
   30.54 +    obj["y"] = 0;
   30.55 +    Object.defineProperty(obj, "z", {value: 0.5});
   30.56 +    var map = Debug.map(obj);
   30.57 +    for (var key in obj) {
   30.58 +        var prop = map.findProperty(key);
   30.59 +        if (prop.hasDualFields() !== dualFields) {
   30.60 +            throw new Error("Wrong property flags: " + prop);
   30.61 +        }
   30.62 +        if (prop.getType() != getExpectedType(obj[key])) {
   30.63 +            throw new Error("Wrong property type: " + prop.getType() + " // " + getExpectedType(obj[key]));
   30.64 +
   30.65 +        }
   30.66 +    }
   30.67 +}
   30.68 +
   30.69 +function getExpectedType(value) {
   30.70 +    if (!dualFields) {
   30.71 +        return objectType.class;
   30.72 +    }
   30.73 +    if (JSType.isRepresentableAsInt(value)) {
   30.74 +        return intType.class;
   30.75 +    }
   30.76 +    if (JSType.isRepresentableAsLong(value)) {
   30.77 +        return longType.class;
   30.78 +    }
   30.79 +    if (JSType.isNumber(value)) {
   30.80 +        return doubleType.class;
   30.81 +    }
   30.82 +    return objectType.class;
   30.83 +}
   30.84 +
   30.85 +var o = {
   30.86 +    a: 1,
   30.87 +    b: 2.5,
   30.88 +    c: 0x10000000000,
   30.89 +    d: true
   30.90 +};
   30.91 +
   30.92 +function C() {
   30.93 +    this.a = 1;
   30.94 +    this.b = 2.5;
   30.95 +    this.c = 0x10000000000;
   30.96 +    this.d = true;
   30.97 +}
   30.98 +
   30.99 +var a = 1;
  30.100 +var b = 2.5;
  30.101 +var c = 0x10000000000;
  30.102 +var d = true;
  30.103 +
  30.104 +testMap(o);
  30.105 +testMap(new C());
  30.106 +testMap(JSON.parse('{ "a": 1, "b": 2.5, "c": 1099511627776, "d": true }'));
  30.107 +testMap(this);

mercurial