001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.codegen; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.asm4.MethodVisitor; 022 import org.jetbrains.asm4.Type; 023 import org.jetbrains.asm4.commons.InstructionAdapter; 024 import org.jetbrains.jet.codegen.context.CodegenContext; 025 import org.jetbrains.jet.codegen.context.FieldOwnerContext; 026 import org.jetbrains.jet.codegen.context.MethodContext; 027 import org.jetbrains.jet.codegen.context.ScriptContext; 028 import org.jetbrains.jet.codegen.signature.JvmMethodSignature; 029 import org.jetbrains.jet.codegen.state.GenerationState; 030 import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 031 import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; 032 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 033 import org.jetbrains.jet.lang.psi.*; 034 import org.jetbrains.jet.lang.resolve.BindingContext; 035 036 import java.util.Collections; 037 import java.util.List; 038 039 import static org.jetbrains.asm4.Opcodes.*; 040 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; 041 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; 042 043 public class ScriptCodegen extends MemberCodegen { 044 045 public static ScriptCodegen createScriptCodegen( 046 @NotNull JetScript declaration, 047 @NotNull GenerationState state, 048 @NotNull CodegenContext parentContext 049 ) { 050 ScriptDescriptor scriptDescriptor = state.getBindingContext().get(BindingContext.SCRIPT, declaration); 051 assert scriptDescriptor != null; 052 053 ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor); 054 assert classDescriptorForScript != null; 055 056 Type className = state.getBindingContext().get(ASM_TYPE, classDescriptorForScript); 057 assert className != null; 058 059 ClassBuilder builder = state.getFactory().newVisitor(className, declaration.getContainingFile()); 060 ScriptContext scriptContext = parentContext.intoScript(scriptDescriptor, classDescriptorForScript); 061 return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter(), builder); 062 } 063 064 @NotNull 065 private JetScript scriptDeclaration; 066 067 @NotNull 068 private final ScriptContext context; 069 070 @NotNull 071 private List<ScriptDescriptor> earlierScripts; 072 073 private ScriptCodegen( 074 @NotNull JetScript scriptDeclaration, 075 @NotNull GenerationState state, 076 @NotNull ScriptContext context, 077 @Nullable List<ScriptDescriptor> earlierScripts, 078 @NotNull ClassBuilder builder 079 ) { 080 super(state, null, context, builder); 081 this.scriptDeclaration = scriptDeclaration; 082 this.context = context; 083 this.earlierScripts = earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts; 084 } 085 086 public void generate() { 087 ScriptDescriptor scriptDescriptor = context.getScriptDescriptor(); 088 ClassDescriptor classDescriptorForScript = context.getContextDescriptor(); 089 Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); 090 assert classType != null; 091 092 ClassBuilder classBuilder = getBuilder(); 093 classBuilder.defineClass(scriptDeclaration, 094 V1_6, 095 ACC_PUBLIC, 096 classType.getInternalName(), 097 null, 098 "java/lang/Object", 099 new String[0]); 100 101 genMembers(context, classBuilder); 102 genFieldsForParameters(scriptDescriptor, classBuilder); 103 genConstructor(scriptDescriptor, classDescriptorForScript, classBuilder, 104 context.intoFunction(scriptDescriptor.getScriptCodeDescriptor())); 105 106 classBuilder.done(); 107 } 108 109 private void genConstructor( 110 @NotNull ScriptDescriptor scriptDescriptor, 111 @NotNull ClassDescriptor classDescriptorForScript, 112 @NotNull ClassBuilder classBuilder, 113 @NotNull MethodContext context 114 ) { 115 116 Type blockType = typeMapper.mapType(scriptDescriptor.getReturnType()); 117 118 classBuilder.newField(null, ACC_PUBLIC | ACC_FINAL, ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 119 blockType.getDescriptor(), null, null); 120 121 JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, earlierScripts); 122 123 MethodVisitor mv = classBuilder.newMethod( 124 scriptDeclaration, ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(), 125 null, null); 126 127 mv.visitCode(); 128 129 InstructionAdapter instructionAdapter = new InstructionAdapter(mv); 130 131 Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); 132 assert classType != null; 133 134 instructionAdapter.load(0, classType); 135 instructionAdapter.invokespecial("java/lang/Object", "<init>", "()V"); 136 137 instructionAdapter.load(0, classType); 138 139 FrameMap frameMap = context.prepareFrame(typeMapper); 140 141 for (ScriptDescriptor importedScript : earlierScripts) { 142 frameMap.enter(importedScript, OBJECT_TYPE); 143 } 144 145 Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes(); 146 int add = 0; 147 148 for (int i = 0; i < scriptDescriptor.getValueParameters().size(); i++) { 149 ValueParameterDescriptor parameter = scriptDescriptor.getValueParameters().get(i); 150 frameMap.enter(parameter, argTypes[i + add]); 151 } 152 153 ImplementationBodyCodegen.generateInitializers( 154 new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state, this), 155 scriptDeclaration.getDeclarations(), 156 bindingContext, 157 state); 158 159 int offset = 1; 160 161 for (ScriptDescriptor earlierScript : earlierScripts) { 162 Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript); 163 instructionAdapter.load(0, classType); 164 instructionAdapter.load(offset, earlierClassType); 165 offset += earlierClassType.getSize(); 166 instructionAdapter.putfield(classType.getInternalName(), getScriptFieldName(earlierScript), earlierClassType.getDescriptor()); 167 } 168 169 for (ValueParameterDescriptor parameter : scriptDescriptor.getValueParameters()) { 170 Type parameterType = typeMapper.mapType(parameter.getType()); 171 instructionAdapter.load(0, classType); 172 instructionAdapter.load(offset, parameterType); 173 offset += parameterType.getSize(); 174 instructionAdapter.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor()); 175 } 176 177 StackValue stackValue = 178 new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state, this).gen(scriptDeclaration.getBlockExpression()); 179 if (stackValue.type != Type.VOID_TYPE) { 180 stackValue.put(stackValue.type, instructionAdapter); 181 instructionAdapter.putfield(classType.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 182 blockType.getDescriptor()); 183 } 184 185 instructionAdapter.areturn(Type.VOID_TYPE); 186 mv.visitMaxs(-1, -1); 187 mv.visitEnd(); 188 } 189 190 private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) { 191 for (ScriptDescriptor earlierScript : earlierScripts) { 192 Type earlierClassName = asmTypeForScriptDescriptor(bindingContext, earlierScript); 193 int access = ACC_PRIVATE | ACC_FINAL; 194 classBuilder.newField(null, access, getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null); 195 } 196 197 for (ValueParameterDescriptor parameter : script.getValueParameters()) { 198 Type parameterType = typeMapper.mapType(parameter); 199 int access = ACC_PUBLIC | ACC_FINAL; 200 classBuilder.newField(null, access, parameter.getName().getIdentifier(), parameterType.getDescriptor(), null, null); 201 } 202 } 203 204 private void genMembers(@NotNull FieldOwnerContext context, @NotNull ClassBuilder classBuilder) { 205 for (JetDeclaration decl : scriptDeclaration.getDeclarations()) { 206 genFunctionOrProperty(context, (JetTypeParameterListOwner) decl, classBuilder); 207 } 208 } 209 210 private int getScriptIndex(@NotNull ScriptDescriptor scriptDescriptor) { 211 int index = earlierScripts.indexOf(scriptDescriptor); 212 if (index < 0) { 213 throw new IllegalStateException("Unregistered script: " + scriptDescriptor); 214 } 215 return index + 1; 216 } 217 218 public String getScriptFieldName(@NotNull ScriptDescriptor scriptDescriptor) { 219 return "script$" + getScriptIndex(scriptDescriptor); 220 } 221 }