SpillObjectCreator.java revision 1261:231d6fd660b8
1/* 2 * Copyright (c) 2010-2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.codegen; 27 28import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; 29import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; 30 31import java.util.LinkedHashSet; 32import java.util.List; 33import java.util.Set; 34import jdk.nashorn.internal.codegen.types.Type; 35import jdk.nashorn.internal.ir.Expression; 36import jdk.nashorn.internal.ir.LiteralNode; 37import jdk.nashorn.internal.runtime.JSType; 38import jdk.nashorn.internal.runtime.Property; 39import jdk.nashorn.internal.runtime.PropertyMap; 40import jdk.nashorn.internal.runtime.ScriptObject; 41import jdk.nashorn.internal.runtime.ScriptRuntime; 42import jdk.nashorn.internal.runtime.arrays.ArrayData; 43import jdk.nashorn.internal.runtime.arrays.ArrayIndex; 44import jdk.nashorn.internal.scripts.JD; 45import jdk.nashorn.internal.scripts.JO; 46 47/** 48 * An object creator that uses spill properties. 49 */ 50public final class SpillObjectCreator extends ObjectCreator<Expression> { 51 52 /** 53 * Constructor 54 * 55 * @param codegen code generator 56 * @param tuples tuples for key, symbol, value 57 */ 58 SpillObjectCreator(final CodeGenerator codegen, final List<MapTuple<Expression>> tuples) { 59 super(codegen, tuples, false, false); 60 makeMap(); 61 } 62 63 @Override 64 protected void makeObject(final MethodEmitter method) { 65 assert !isScope() : "spill scope objects are not currently supported"; 66 67 final int length = tuples.size(); 68 final boolean dualFields = codegen.useDualFields(); 69 final int spillLength = ScriptObject.spillAllocationLength(length); 70 final long[] jpresetValues = dualFields ? new long[spillLength] : null; 71 final Object[] opresetValues = new Object[spillLength]; 72 final Set<Integer> postsetValues = new LinkedHashSet<>(); 73 final int callSiteFlags = codegen.getCallSiteFlags(); 74 final Class<?> objectClass = dualFields ? JD.class : JO.class; 75 ArrayData arrayData = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY); 76 77 // Compute constant property values 78 int pos = 0; 79 for (final MapTuple<Expression> tuple : tuples) { 80 final String key = tuple.key; 81 final Expression value = tuple.value; 82 83 //this is a nop of tuple.key isn't e.g. "apply" or another special name 84 method.invalidateSpecialName(tuple.key); 85 86 if (value != null) { 87 final Object constantValue = LiteralNode.objectAsConstant(value); 88 if (constantValue == LiteralNode.POSTSET_MARKER) { 89 postsetValues.add(pos); 90 } else { 91 final Property property = propertyMap.findProperty(key); 92 if (property != null) { 93 // normal property key 94 property.setType(dualFields ? JSType.unboxedFieldType(constantValue) : Object.class); 95 final int slot = property.getSlot(); 96 if (dualFields && constantValue instanceof Number) { 97 jpresetValues[slot] = ObjectClassGenerator.pack((Number)constantValue); 98 } else { 99 opresetValues[slot] = constantValue; 100 } 101 } else { 102 // array index key 103 final long oldLength = arrayData.length(); 104 final int index = ArrayIndex.getArrayIndex(key); 105 final long longIndex = ArrayIndex.toLongIndex(index); 106 107 assert ArrayIndex.isValidArrayIndex(index); 108 109 if (longIndex >= oldLength) { 110 arrayData = arrayData.ensure(longIndex); 111 } 112 113 //avoid blowing up the array if we can 114 if (constantValue instanceof Integer) { 115 arrayData = arrayData.set(index, ((Integer)constantValue).intValue(), false); 116 } else if (constantValue instanceof Long) { 117 arrayData = arrayData.set(index, ((Long)constantValue).longValue(), false); 118 } else if (constantValue instanceof Double) { 119 arrayData = arrayData.set(index, ((Double)constantValue).doubleValue(), false); 120 } else { 121 arrayData = arrayData.set(index, constantValue, false); 122 } 123 124 if (longIndex > oldLength) { 125 arrayData = arrayData.delete(oldLength, longIndex - 1); 126 } 127 } 128 } 129 } 130 pos++; 131 } 132 133 // create object and invoke constructor 134 method._new(objectClass).dup(); 135 codegen.loadConstant(propertyMap); 136 137 // load primitive value spill array 138 if (dualFields) { 139 codegen.loadConstant(jpresetValues); 140 } else { 141 method.loadNull(); 142 } 143 // load object value spill array 144 codegen.loadConstant(opresetValues); 145 146 // instantiate the script object with spill objects 147 method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class)); 148 149 helpOptimisticRecognizeDuplicateIdentity(method); 150 151 // Set prefix array data if any 152 if (arrayData.length() > 0) { 153 method.dup(); 154 codegen.loadConstant(arrayData); 155 method.invoke(virtualCallNoLookup(ScriptObject.class, "setArray", void.class, ArrayData.class)); 156 } 157 158 // set postfix values 159 for (final int i : postsetValues) { 160 final MapTuple<Expression> tuple = tuples.get(i); 161 final Property property = propertyMap.findProperty(tuple.key); 162 if (property == null) { 163 final int index = ArrayIndex.getArrayIndex(tuple.key); 164 assert ArrayIndex.isValidArrayIndex(index); 165 method.dup(); 166 method.load(ArrayIndex.toLongIndex(index)); 167 //method.println("putting " + tuple + " into arraydata"); 168 loadTuple(method, tuple); 169 method.dynamicSetIndex(callSiteFlags); 170 } else { 171 method.dup(); 172 loadTuple(method, tuple); 173 method.dynamicSet(property.getKey(), codegen.getCallSiteFlags(), false); 174 } 175 } 176 } 177 178 @Override 179 protected PropertyMap makeMap() { 180 assert propertyMap == null : "property map already initialized"; 181 final boolean dualFields = codegen.useDualFields(); 182 final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class; 183 propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields()); 184 return propertyMap; 185 } 186 187 @Override 188 protected void loadValue(final Expression expr, final Type type) { 189 codegen.loadExpressionAsType(expr, type); 190 } 191} 192