src/jdk/nashorn/internal/codegen/FieldObjectCreator.java

Thu, 24 May 2018 16:39:31 +0800

author
aoqi
date
Thu, 24 May 2018 16:39:31 +0800
changeset 1959
61ffdd1b89f2
parent 1720
c09b105e7be5
parent 1490
d85f981c8cf8
permissions
-rw-r--r--

Merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package jdk.nashorn.internal.codegen;
aoqi@0 27
aoqi@0 28 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS;
aoqi@0 29 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup;
aoqi@0 30 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
attila@963 31 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
attila@963 32 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getFieldName;
aoqi@0 33 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.getPaddedFieldCount;
aoqi@0 34 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
aoqi@0 35 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
aoqi@0 36
aoqi@0 37 import java.util.List;
aoqi@0 38 import jdk.nashorn.internal.codegen.types.Type;
aoqi@0 39 import jdk.nashorn.internal.ir.Symbol;
aoqi@0 40 import jdk.nashorn.internal.runtime.Context;
aoqi@0 41 import jdk.nashorn.internal.runtime.JSType;
aoqi@0 42 import jdk.nashorn.internal.runtime.PropertyMap;
aoqi@0 43 import jdk.nashorn.internal.runtime.ScriptObject;
aoqi@0 44 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
aoqi@0 45
aoqi@0 46 /**
aoqi@0 47 * Analyze an object's characteristics for appropriate code generation. This
aoqi@0 48 * is used for functions and for objects. A field object take a set of values which
aoqi@0 49 * to assign to the various fields in the object. This is done by the generated code
aoqi@0 50 *
aoqi@0 51 * @param <T> the value type for the fields being written on object creation, e.g. Node
aoqi@0 52 * @see jdk.nashorn.internal.ir.Node
aoqi@0 53 */
attila@963 54 public abstract class FieldObjectCreator<T> extends ObjectCreator<T> {
aoqi@0 55
attila@963 56 private String fieldObjectClassName;
attila@963 57 private Class<? extends ScriptObject> fieldObjectClass;
attila@963 58 private int fieldCount;
attila@963 59 private int paddedFieldCount;
attila@963 60 private int paramCount;
aoqi@0 61
aoqi@0 62 /** call site flags to be used for invocations */
attila@963 63 private final int callSiteFlags;
attila@963 64 /** are we creating this field object from 'eval' code? */
attila@963 65 private final boolean evalCode;
aoqi@0 66
aoqi@0 67 /**
aoqi@0 68 * Constructor
aoqi@0 69 *
aoqi@0 70 * @param codegen code generator
hannesw@991 71 * @param tuples tuples for fields in object
aoqi@0 72 */
attila@963 73 FieldObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples) {
attila@963 74 this(codegen, tuples, false, false);
aoqi@0 75 }
aoqi@0 76
aoqi@0 77 /**
aoqi@0 78 * Constructor
aoqi@0 79 *
aoqi@0 80 * @param codegen code generator
hannesw@991 81 * @param tuples tuples for fields in object
aoqi@0 82 * @param isScope is this a scope object
aoqi@0 83 * @param hasArguments does the created object have an "arguments" property
aoqi@0 84 */
attila@963 85 FieldObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples, final boolean isScope, final boolean hasArguments) {
attila@963 86 super(codegen, tuples, isScope, hasArguments);
aoqi@0 87 this.callSiteFlags = codegen.getCallSiteFlags();
attila@963 88 this.evalCode = codegen.isEvalCode();
aoqi@0 89 countFields();
aoqi@0 90 findClass();
aoqi@0 91 }
aoqi@0 92
aoqi@0 93 @Override
hannesw@1542 94 public void createObject(final MethodEmitter method) {
aoqi@0 95 makeMap();
attila@963 96 final String className = getClassName();
hannesw@1542 97 // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
hannesw@1542 98 // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
hannesw@1542 99 // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
hannesw@1542 100 // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
hannesw@1542 101 // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
hannesw@1542 102 // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
hannesw@1542 103 // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
hannesw@1542 104 assert fieldObjectClass != null;
hannesw@1542 105 method._new(fieldObjectClass).dup();
hannesw@1542 106
aoqi@0 107 loadMap(method); //load the map
aoqi@0 108
aoqi@0 109 if (isScope()) {
aoqi@0 110 loadScope(method);
aoqi@0 111
aoqi@0 112 if (hasArguments()) {
aoqi@0 113 method.loadCompilerConstant(ARGUMENTS);
attila@963 114 method.invoke(constructorNoLookup(className, PropertyMap.class, ScriptObject.class, ARGUMENTS.type()));
aoqi@0 115 } else {
attila@963 116 method.invoke(constructorNoLookup(className, PropertyMap.class, ScriptObject.class));
aoqi@0 117 }
aoqi@0 118 } else {
attila@963 119 method.invoke(constructorNoLookup(className, PropertyMap.class));
aoqi@0 120 }
hannesw@1542 121 }
aoqi@0 122
hannesw@1542 123 @Override
hannesw@1542 124 public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
hannesw@1542 125 method.load(objectType, objectSlot);
aoqi@0 126 // Set values.
hannesw@1542 127 for (int i = start; i < end; i++) {
hannesw@1542 128 final MapTuple<T> tuple = tuples.get(i);
attila@963 129 //we only load when we have both symbols and values (which can be == the symbol)
attila@963 130 //if we didn't load, we need an array property
attila@963 131 if (tuple.symbol != null && tuple.value != null) {
attila@963 132 final int index = getArrayIndex(tuple.key);
attila@1344 133 method.dup();
attila@963 134 if (!isValidArrayIndex(index)) {
attila@963 135 putField(method, tuple.key, tuple.symbol.getFieldIndex(), tuple);
attila@963 136 } else {
attila@963 137 putSlot(method, ArrayIndex.toLongIndex(index), tuple);
attila@963 138 }
aoqi@0 139
attila@963 140 //this is a nop of tuple.key isn't e.g. "apply" or another special name
attila@963 141 method.invalidateSpecialName(tuple.key);
aoqi@0 142 }
aoqi@0 143 }
aoqi@0 144 }
aoqi@0 145
aoqi@0 146 @Override
aoqi@0 147 protected PropertyMap makeMap() {
aoqi@0 148 assert propertyMap == null : "property map already initialized";
hannesw@1330 149 propertyMap = newMapCreator(fieldObjectClass).makeFieldMap(hasArguments(), codegen.useDualFields(), fieldCount, paddedFieldCount, evalCode);
aoqi@0 150 return propertyMap;
aoqi@0 151 }
aoqi@0 152
aoqi@0 153 /**
aoqi@0 154 * Store a value in a field of the generated class object.
aoqi@0 155 *
aoqi@0 156 * @param method Script method.
aoqi@0 157 * @param key Property key.
aoqi@0 158 * @param fieldIndex Field number.
hannesw@991 159 * @param tuple Tuple to store.
aoqi@0 160 */
attila@963 161 private void putField(final MethodEmitter method, final String key, final int fieldIndex, final MapTuple<T> tuple) {
hannesw@1330 162 final Type fieldType = codegen.useDualFields() && tuple.isPrimitive() ? PRIMITIVE_FIELD_TYPE : Type.OBJECT;
attila@963 163 final String fieldClass = getClassName();
attila@963 164 final String fieldName = getFieldName(fieldIndex, fieldType);
attila@963 165 final String fieldDesc = typeDescriptor(fieldType.getTypeClass());
attila@963 166
attila@963 167 assert fieldName.equals(getFieldName(fieldIndex, PRIMITIVE_FIELD_TYPE)) || fieldType.isObject() : key + " object keys must store to L*-fields";
attila@963 168 assert fieldName.equals(getFieldName(fieldIndex, Type.OBJECT)) || fieldType.isPrimitive() : key + " primitive keys must store to J*-fields";
attila@963 169
hannesw@1720 170 loadTuple(method, tuple, true);
attila@963 171 method.putField(fieldClass, fieldName, fieldDesc);
aoqi@0 172 }
aoqi@0 173
aoqi@0 174 /**
aoqi@0 175 * Store a value in an indexed slot of a generated class object.
aoqi@0 176 *
aoqi@0 177 * @param method Script method.
aoqi@0 178 * @param index Slot index.
hannesw@991 179 * @param tuple Tuple to store.
aoqi@0 180 */
attila@963 181 private void putSlot(final MethodEmitter method, final long index, final MapTuple<T> tuple) {
hannesw@1720 182 loadIndex(method, index);
attila@963 183 loadTuple(method, tuple, false); //we don't pack array like objects
aoqi@0 184 method.dynamicSetIndex(callSiteFlags);
aoqi@0 185 }
aoqi@0 186
aoqi@0 187 /**
aoqi@0 188 * Locate (or indirectly create) the object container class.
aoqi@0 189 */
aoqi@0 190 private void findClass() {
aoqi@0 191 fieldObjectClassName = isScope() ?
hannesw@1330 192 ObjectClassGenerator.getClassName(fieldCount, paramCount, codegen.useDualFields()) :
hannesw@1330 193 ObjectClassGenerator.getClassName(paddedFieldCount, codegen.useDualFields());
aoqi@0 194
aoqi@0 195 try {
aoqi@0 196 this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
aoqi@0 197 } catch (final ClassNotFoundException e) {
aoqi@0 198 throw new AssertionError("Nashorn has encountered an internal error. Structure can not be created.");
aoqi@0 199 }
aoqi@0 200 }
aoqi@0 201
hannesw@1542 202 @Override
hannesw@1542 203 protected Class<? extends ScriptObject> getAllocatorClass() {
hannesw@1542 204 return fieldObjectClass;
hannesw@1542 205 }
hannesw@1542 206
aoqi@0 207 /**
aoqi@0 208 * Get the class name for the object class,
aoqi@0 209 * e.g. {@code com.nashorn.oracle.scripts.JO2P0}
aoqi@0 210 *
aoqi@0 211 * @return script class name
aoqi@0 212 */
aoqi@0 213 String getClassName() {
aoqi@0 214 return fieldObjectClassName;
aoqi@0 215 }
aoqi@0 216
aoqi@0 217 /**
aoqi@0 218 * Tally the number of fields and parameters.
aoqi@0 219 */
aoqi@0 220 private void countFields() {
attila@963 221 for (final MapTuple<T> tuple : tuples) {
attila@963 222 final Symbol symbol = tuple.symbol;
aoqi@0 223 if (symbol != null) {
aoqi@0 224 if (hasArguments() && symbol.isParam()) {
aoqi@0 225 symbol.setFieldIndex(paramCount++);
hannesw@1014 226 } else if (!isValidArrayIndex(getArrayIndex(tuple.key))) {
aoqi@0 227 symbol.setFieldIndex(fieldCount++);
aoqi@0 228 }
aoqi@0 229 }
aoqi@0 230 }
aoqi@0 231
aoqi@0 232 paddedFieldCount = getPaddedFieldCount(fieldCount);
aoqi@0 233 }
aoqi@0 234
aoqi@0 235 }

mercurial