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 ScriptContext scriptContext = parentContext.intoScript(scriptDescriptor, classDescriptorForScript); 057 return new ScriptCodegen(declaration, state, scriptContext, state.getEarlierScriptsForReplInterpreter()); 058 } 059 060 @NotNull 061 private JetScript scriptDeclaration; 062 063 @NotNull 064 private final ScriptContext context; 065 066 @NotNull 067 private List<ScriptDescriptor> earlierScripts; 068 069 private ScriptCodegen( 070 @NotNull JetScript scriptDeclaration, 071 @NotNull GenerationState state, 072 @NotNull ScriptContext context, 073 @Nullable List<ScriptDescriptor> earlierScripts 074 ) { 075 super(state, null); 076 this.scriptDeclaration = scriptDeclaration; 077 this.context = context; 078 this.earlierScripts = earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts; 079 } 080 081 public void generate() { 082 ScriptDescriptor scriptDescriptor = context.getScriptDescriptor(); 083 ClassDescriptor classDescriptorForScript = context.getContextDescriptor(); 084 Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); 085 assert classType != null; 086 087 ClassBuilder classBuilder = state.getFactory().newVisitor(classType, scriptDeclaration.getContainingFile()); 088 089 classBuilder.defineClass(scriptDeclaration, 090 V1_6, 091 ACC_PUBLIC, 092 classType.getInternalName(), 093 null, 094 "java/lang/Object", 095 new String[0]); 096 097 genMembers(context, classBuilder); 098 genFieldsForParameters(scriptDescriptor, classBuilder); 099 genConstructor(scriptDescriptor, classDescriptorForScript, classBuilder, 100 context.intoFunction(scriptDescriptor.getScriptCodeDescriptor())); 101 102 classBuilder.done(); 103 } 104 105 private void genConstructor( 106 @NotNull ScriptDescriptor scriptDescriptor, 107 @NotNull ClassDescriptor classDescriptorForScript, 108 @NotNull ClassBuilder classBuilder, 109 @NotNull MethodContext context 110 ) { 111 112 Type blockType = typeMapper.mapType(scriptDescriptor.getReturnType()); 113 114 classBuilder.newField(null, ACC_PUBLIC | ACC_FINAL, ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 115 blockType.getDescriptor(), null, null); 116 117 JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, earlierScripts); 118 119 MethodVisitor mv = classBuilder.newMethod( 120 scriptDeclaration, ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(), 121 null, null); 122 123 mv.visitCode(); 124 125 InstructionAdapter instructionAdapter = new InstructionAdapter(mv); 126 127 Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); 128 assert classType != null; 129 130 instructionAdapter.load(0, classType); 131 instructionAdapter.invokespecial("java/lang/Object", "<init>", "()V"); 132 133 instructionAdapter.load(0, classType); 134 135 FrameMap frameMap = context.prepareFrame(typeMapper); 136 137 for (ScriptDescriptor importedScript : earlierScripts) { 138 frameMap.enter(importedScript, OBJECT_TYPE); 139 } 140 141 Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes(); 142 int add = 0; 143 144 for (int i = 0; i < scriptDescriptor.getValueParameters().size(); i++) { 145 ValueParameterDescriptor parameter = scriptDescriptor.getValueParameters().get(i); 146 frameMap.enter(parameter, argTypes[i + add]); 147 } 148 149 ImplementationBodyCodegen.generateInitializers( 150 new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, context, state, this), 151 scriptDeclaration.getDeclarations(), 152 bindingContext, 153 state); 154 155 int offset = 1; 156 157 for (ScriptDescriptor earlierScript : earlierScripts) { 158 Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript); 159 instructionAdapter.load(0, classType); 160 instructionAdapter.load(offset, earlierClassType); 161 offset += earlierClassType.getSize(); 162 instructionAdapter.putfield(classType.getInternalName(), getScriptFieldName(earlierScript), earlierClassType.getDescriptor()); 163 } 164 165 for (ValueParameterDescriptor parameter : scriptDescriptor.getValueParameters()) { 166 Type parameterType = typeMapper.mapType(parameter.getType()); 167 instructionAdapter.load(0, classType); 168 instructionAdapter.load(offset, parameterType); 169 offset += parameterType.getSize(); 170 instructionAdapter.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor()); 171 } 172 173 StackValue stackValue = 174 new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, context, state, this).gen(scriptDeclaration.getBlockExpression()); 175 if (stackValue.type != Type.VOID_TYPE) { 176 stackValue.put(stackValue.type, instructionAdapter); 177 instructionAdapter.putfield(classType.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 178 blockType.getDescriptor()); 179 } 180 181 instructionAdapter.areturn(Type.VOID_TYPE); 182 mv.visitMaxs(-1, -1); 183 mv.visitEnd(); 184 } 185 186 private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) { 187 for (ScriptDescriptor earlierScript : earlierScripts) { 188 Type earlierClassName = asmTypeForScriptDescriptor(bindingContext, earlierScript); 189 int access = ACC_PRIVATE | ACC_FINAL; 190 classBuilder.newField(null, access, getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null); 191 } 192 193 for (ValueParameterDescriptor parameter : script.getValueParameters()) { 194 Type parameterType = typeMapper.mapType(parameter); 195 int access = ACC_PUBLIC | ACC_FINAL; 196 classBuilder.newField(null, access, parameter.getName().getIdentifier(), parameterType.getDescriptor(), null, null); 197 } 198 } 199 200 private void genMembers(@NotNull FieldOwnerContext context, @NotNull ClassBuilder classBuilder) { 201 for (JetDeclaration decl : scriptDeclaration.getDeclarations()) { 202 genFunctionOrProperty(context, (JetTypeParameterListOwner) decl, classBuilder); 203 } 204 } 205 206 private int getScriptIndex(@NotNull ScriptDescriptor scriptDescriptor) { 207 int index = earlierScripts.indexOf(scriptDescriptor); 208 if (index < 0) { 209 throw new IllegalStateException("Unregistered script: " + scriptDescriptor); 210 } 211 return index + 1; 212 } 213 214 public String getScriptFieldName(@NotNull ScriptDescriptor scriptDescriptor) { 215 return "script$" + getScriptIndex(scriptDescriptor); 216 } 217 }