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 26 package jdk.nashorn.internal.codegen; 27 28 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex; 29 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 import jdk.nashorn.internal.ir.Symbol; 34 import jdk.nashorn.internal.runtime.AccessorProperty; 35 import jdk.nashorn.internal.runtime.Property; 36 import jdk.nashorn.internal.runtime.PropertyMap; 37 import jdk.nashorn.internal.runtime.ScriptObject; 38 import jdk.nashorn.internal.runtime.SpillProperty; 39 40 /** 41 * Class that creates PropertyMap sent to script object constructors. 42 * @param <T> value type for tuples, e.g. Symbol 43 */ 44 public class MapCreator<T> { 45 /** Object structure for objects associated with this map */ 46 private final Class<?> structure; 47 48 /** key set for object map */ 49 private final List<MapTuple<T>> tuples; 50 51 /** 52 * Constructor 53 * 54 * @param structure structure to generate map for (a JO subclass) 55 * @param tuples list of tuples for map 56 */ 57 MapCreator(final Class<? extends ScriptObject> structure, final List<MapTuple<T>> tuples) { 58 this.structure = structure; 59 this.tuples = tuples; 60 } 61 62 /** 63 * Constructs a property map based on a set of fields. 64 * 65 * @param hasArguments does the created object have an "arguments" property 66 * @param fieldCount Number of fields in use. 67 * @param fieldMaximum Number of fields available. 68 * @param evalCode is this property map created for 'eval' code? 69 * @return New map populated with accessor properties. 70 */ 71 PropertyMap makeFieldMap(final boolean hasArguments, final int fieldCount, final int fieldMaximum, final boolean evalCode) { 72 final List<Property> properties = new ArrayList<>(); 73 assert tuples != null; 74 75 for (final MapTuple<T> tuple : tuples) { 76 final String key = tuple.key; 77 final Symbol symbol = tuple.symbol; 78 final Class<?> initialType = tuple.getValueType(); 79 80 if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) { 81 final int flags = getPropertyFlags(symbol, hasArguments, evalCode); 82 final Property property = new AccessorProperty( 83 key, 84 flags, 85 structure, 86 symbol.getFieldIndex(), 87 initialType); 88 properties.add(property); 89 } 90 } 91 92 return PropertyMap.newMap(properties, structure.getName(), fieldCount, fieldMaximum, 0); 93 } 94 95 PropertyMap makeSpillMap(final boolean hasArguments) { 96 final List<Property> properties = new ArrayList<>(); 97 int spillIndex = 0; 98 assert tuples != null; 99 100 for (final MapTuple<T> tuple : tuples) { 101 final String key = tuple.key; 102 final Symbol symbol = tuple.symbol; 103 final Class<?> initialType = tuple.getValueType(); 104 105 //TODO initial type is object here no matter what. Is that right? 106 if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) { 107 final int flags = getPropertyFlags(symbol, hasArguments, false); 108 properties.add( 109 new SpillProperty( 110 key, 111 flags, 112 spillIndex++, 113 initialType)); 114 } 115 } 116 117 return PropertyMap.newMap(properties, structure.getName(), 0, 0, spillIndex); 118 } 119 120 /** 121 * Compute property flags given local state of a field. May be overridden and extended, 122 * 123 * @param symbol symbol to check 124 * @param hasArguments does the created object have an "arguments" property 125 * 126 * @return flags to use for fields 127 */ 128 static int getPropertyFlags(final Symbol symbol, final boolean hasArguments, final boolean evalCode) { 129 int flags = 0; 130 131 if (symbol.isParam()) { 132 flags |= Property.IS_PARAMETER; 133 } 134 135 if (hasArguments) { 136 flags |= Property.HAS_ARGUMENTS; 137 } 138 139 // See ECMA 5.1 10.5 Declaration Binding Instantiation. 140 // Step 2 If code is eval code, then let configurableBindings 141 // be true else let configurableBindings be false. 142 // We have to make vars, functions declared in 'eval' code 143 // configurable. But vars, functions from any other code is 144 // not configurable. 145 if (symbol.isScope() && !evalCode) { 146 flags |= Property.NOT_CONFIGURABLE; 147 } 148 149 if (symbol.isFunctionDeclaration()) { 150 flags |= Property.IS_FUNCTION_DECLARATION; 151 } 152 153 if (symbol.isConst()) { 154 flags |= Property.NOT_WRITABLE; 155 } 156 157 if (symbol.isBlockScoped()) { 158 flags |= Property.IS_LEXICAL_BINDING; 159 } 160 161 // Mark symbol as needing declaration. Access before declaration will throw a ReferenceError. 162 if (symbol.isBlockScoped() && symbol.isScope()) { 163 flags |= Property.NEEDS_DECLARATION; 164 } 165 166 return flags; 167 } 168 }