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.objects;
  27 
  28 import java.util.List;
  29 import jdk.nashorn.internal.codegen.CodeGenerator;
  30 import jdk.nashorn.internal.codegen.CompileUnit;
  31 import jdk.nashorn.internal.codegen.Compiler;
  32 import jdk.nashorn.internal.codegen.MethodEmitter;
  33 import jdk.nashorn.internal.ir.Symbol;
  34 import jdk.nashorn.internal.runtime.Context;
  35 import jdk.nashorn.internal.runtime.PropertyMap;
  36 
  37 /**
  38  * Base class for object creation code generation.
  39  */
  40 public abstract class ObjectCreator {
  41 
  42     /** Compile unit for this ObjectCreator, see CompileUnit */
  43     protected final CompileUnit   compileUnit;
  44 
  45     /** List of keys to initiate in this ObjectCreator */
  46     protected final List<String>  keys;
  47 
  48     /** List of symbols to initiate in this ObjectCreator */
  49     protected final List<Symbol>  symbols;
  50 
  51     /** Code generator */
  52     protected final CodeGenerator codegen;
  53 
  54     private   final boolean       isScope;
  55     private   final boolean       isVarArg;
  56     private         int           fieldCount;
  57     private         int           paramCount;
  58     private         String        fieldObjectClassName;
  59     private         Class<?>      fieldObjectClass;
  60     private         PropertyMap   propertyMap;
  61 
  62     /**
  63      * Constructor
  64      *
  65      * @param codegen  the code generator
  66      * @param keys     the keys
  67      * @param symbols  the symbols corresponding to keys, same index
  68      * @param isScope  is this object scope
  69      * @param isVarArg is this object var arg
  70      */
  71     protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean isVarArg) {
  72         this.codegen       = codegen;
  73         this.compileUnit   = codegen.getCurrentCompileUnit();
  74         this.keys          = keys;
  75         this.symbols       = symbols;
  76         this.isScope       = isScope;
  77         this.isVarArg      = isVarArg;
  78 
  79         countFields();
  80         findClass();
  81     }
  82 
  83     /**
  84      * Tally the number of fields and parameters.
  85      */
  86     private void countFields() {
  87         for (final Symbol symbol : this.symbols) {
  88             if (symbol != null) {
  89                 if (isVarArg() && symbol.isParam()) {
  90                     symbol.setFieldIndex(paramCount++);
  91                 } else {
  92                     symbol.setFieldIndex(fieldCount++);
  93                 }
  94             }
  95         }
  96     }
  97 
  98     /**
  99      * Locate (or indirectly create) the object container class.
 100      */
 101     private void findClass() {
 102         fieldObjectClassName = isScope() ?
 103             ObjectClassGenerator.getClassName(fieldCount, paramCount) :
 104             ObjectClassGenerator.getClassName(fieldCount);
 105 
 106         try {
 107             this.fieldObjectClass = Context.forStructureClass(Compiler.binaryName(fieldObjectClassName));
 108         } catch (final ClassNotFoundException e) {
 109             throw new AssertionError("Nashorn has encountered an internal error.  Structure can not be created.");
 110         }
 111     }
 112 
 113     /**
 114      * Generate code for making the object.
 115      * @param method Script method.
 116      */
 117     public abstract void makeObject(final MethodEmitter method);
 118 
 119     /**
 120      * Create a new MapCreator
 121      * @param clazz type of MapCreator
 122      * @return map creator instantiated by type
 123      */
 124     protected MapCreator newMapCreator(final Class<?> clazz) {
 125         return new MapCreator(clazz, keys, symbols);
 126     }
 127 
 128     /**
 129      * Construct the property map appropriate for the object.
 130      * @return the newly created property map
 131      */
 132     protected PropertyMap makeMap() {
 133         if (keys.isEmpty()) { //empty map
 134             propertyMap = PropertyMap.newMap(fieldObjectClass);
 135         } else {
 136             propertyMap = newMapCreator(fieldObjectClass).makeMap(isVarArg());
 137         }
 138         return propertyMap;
 139     }
 140 
 141     /**
 142      * Emit the correct map for the object.
 143      * @param method method emitter
 144      * @return the method emitter
 145      */
 146     protected MethodEmitter loadMap(final MethodEmitter method) {
 147         codegen.loadConstant(propertyMap);
 148         return method;
 149     }
 150 
 151     /**
 152      * Get the class name for the object class,
 153      * e.g. {@code com.nashorn.oracle.scripts.JO$2P0}
 154      *
 155      * @return script class name
 156      */
 157     public String getClassName() {
 158         return fieldObjectClassName;
 159     }
 160 
 161     /**
 162      * Is this a scope object
 163      * @return true if scope
 164      */
 165     protected boolean isScope() {
 166         return isScope;
 167     }
 168 
 169     /**
 170      * Is this a vararg object
 171      * @return true if vararg
 172      */
 173     protected boolean isVarArg() {
 174         return isVarArg;
 175     }
 176 }