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.codegen.CompilerConstants.SCOPE; 29 30 import java.util.List; 31 import jdk.nashorn.internal.codegen.types.Type; 32 import jdk.nashorn.internal.runtime.JSType; 33 import jdk.nashorn.internal.runtime.PropertyMap; 34 import jdk.nashorn.internal.runtime.ScriptObject; 35 36 /** 37 * Base class for object creation code generation. 38 * @param <T> value type 39 */ 40 public abstract class ObjectCreator<T> implements CodeGenerator.SplitLiteralCreator { 41 42 /** List of keys & symbols to initiate in this ObjectCreator */ 43 final List<MapTuple<T>> tuples; 44 45 /** Code generator */ 46 final CodeGenerator codegen; 47 48 /** Property map */ 49 protected PropertyMap propertyMap; 50 51 private final boolean isScope; 52 private final boolean hasArguments; 53 54 /** 55 * Constructor 56 * 57 * @param codegen the code generator 58 * @param tuples key,symbol,value (optional) tuples 59 * @param isScope is this object scope 60 * @param hasArguments does the created object have an "arguments" property 61 */ 62 ObjectCreator(final CodeGenerator codegen, final List<MapTuple<T>> tuples, final boolean isScope, final boolean hasArguments) { 63 this.codegen = codegen; 64 this.tuples = tuples; 65 this.isScope = isScope; 66 this.hasArguments = hasArguments; 67 } 68 69 /** 70 * Generate code for making the object. 71 * @param method Script method. 72 */ 73 public void makeObject(final MethodEmitter method) { 74 createObject(method); 75 // We need to store the object in a temporary slot as populateRange expects to load the 76 // object from a slot (as it is also invoked within split methods). Note that this also 77 // helps optimistic continuations to handle the stack in case an optimistic assumption 78 // fails during initialization (see JDK-8079269). 79 final int objectSlot = method.getUsedSlotsWithLiveTemporaries(); 80 final Type objectType = method.peekType(); 81 method.storeTemp(objectType, objectSlot); 82 populateRange(method, objectType, objectSlot, 0, tuples.size()); 83 } 84 85 /** 86 * Generate code for creating and initializing the object. 87 * @param method the method emitter 88 */ 89 protected abstract void createObject(final MethodEmitter method); 90 91 /** 92 * Construct the property map appropriate for the object. 93 * @return the newly created property map 94 */ 95 protected abstract PropertyMap makeMap(); 96 97 /** 98 * Create a new MapCreator 99 * @param clazz type of MapCreator 100 * @return map creator instantiated by type 101 */ 102 protected MapCreator<?> newMapCreator(final Class<? extends ScriptObject> clazz) { 103 return new MapCreator<>(clazz, tuples); 104 } 105 106 /** 107 * Loads the scope on the stack through the passed method emitter. 108 * @param method the method emitter to use 109 */ 110 protected void loadScope(final MethodEmitter method) { 111 method.loadCompilerConstant(SCOPE); 112 } 113 114 /** 115 * Emit the correct map for the object. 116 * @param method method emitter 117 * @return the method emitter 118 */ 119 protected MethodEmitter loadMap(final MethodEmitter method) { 120 codegen.loadConstant(propertyMap); 121 return method; 122 } 123 124 PropertyMap getMap() { 125 return propertyMap; 126 } 127 128 /** 129 * Is this a scope object 130 * @return true if scope 131 */ 132 protected boolean isScope() { 133 return isScope; 134 } 135 136 /** 137 * Does the created object have an "arguments" property 138 * @return true if has an "arguments" property 139 */ 140 protected boolean hasArguments() { 141 return hasArguments; 142 } 143 144 /** 145 * Get the class of objects created by this ObjectCreator 146 * @return class of created object 147 */ 148 abstract protected Class<? extends ScriptObject> getAllocatorClass(); 149 150 /** 151 * Technique for loading an initial value. Defined by anonymous subclasses in code gen. 152 * 153 * @param value Value to load. 154 * @param type the type of the value to load 155 */ 156 protected abstract void loadValue(T value, Type type); 157 158 MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple, final boolean pack) { 159 loadValue(tuple.value, tuple.type); 160 if (!codegen.useDualFields() || !tuple.isPrimitive()) { 161 method.convert(Type.OBJECT); 162 } else if (pack) { 163 method.pack(); 164 } 165 return method; 166 } 167 168 MethodEmitter loadIndex(final MethodEmitter method, final long index) { 169 return JSType.isRepresentableAsInt(index) ? method.load((int) index) : method.load((double) index); 170 } 171 }