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 kotlin.Function0; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.jet.codegen.context.CodegenContext; 022 import org.jetbrains.jet.codegen.context.MethodContext; 023 import org.jetbrains.jet.codegen.context.ScriptContext; 024 import org.jetbrains.jet.codegen.state.GenerationState; 025 import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 026 import org.jetbrains.jet.lang.descriptors.ScriptDescriptor; 027 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 028 import org.jetbrains.jet.lang.psi.JetDeclaration; 029 import org.jetbrains.jet.lang.psi.JetScript; 030 import org.jetbrains.jet.lang.resolve.BindingContext; 031 import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; 032 import org.jetbrains.org.objectweb.asm.MethodVisitor; 033 import org.jetbrains.org.objectweb.asm.Type; 034 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 035 036 import java.util.Collections; 037 import java.util.List; 038 039 import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; 040 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; 041 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 042 043 // SCRIPT: script code generator 044 public class ScriptCodegen extends MemberCodegen<JetScript> { 045 046 public static ScriptCodegen createScriptCodegen( 047 @NotNull JetScript declaration, 048 @NotNull GenerationState state, 049 @NotNull CodegenContext parentContext 050 ) { 051 ScriptDescriptor scriptDescriptor = state.getBindingContext().get(BindingContext.SCRIPT, declaration); 052 assert scriptDescriptor != null; 053 054 ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, scriptDescriptor); 055 assert classDescriptorForScript != null; 056 057 Type className = state.getBindingContext().get(ASM_TYPE, classDescriptorForScript); 058 assert className != null; 059 060 ClassBuilder builder = state.getFactory().newVisitor(className, declaration.getContainingFile()); 061 List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter(); 062 ScriptContext scriptContext = parentContext.intoScript( 063 scriptDescriptor, 064 earlierScripts == null ? Collections.<ScriptDescriptor>emptyList() : earlierScripts, 065 classDescriptorForScript 066 ); 067 return new ScriptCodegen(declaration, state, scriptContext, builder); 068 } 069 070 private final JetScript scriptDeclaration; 071 private final ScriptContext context; 072 private final ScriptDescriptor scriptDescriptor; 073 074 private ScriptCodegen( 075 @NotNull JetScript scriptDeclaration, 076 @NotNull GenerationState state, 077 @NotNull ScriptContext context, 078 @NotNull ClassBuilder builder 079 ) { 080 super(state, null, context, scriptDeclaration, builder); 081 this.scriptDeclaration = scriptDeclaration; 082 this.context = context; 083 this.scriptDescriptor = context.getScriptDescriptor(); 084 } 085 086 @Override 087 protected void generateDeclaration() { 088 Type classType = bindingContext.get(ASM_TYPE, context.getContextDescriptor()); 089 assert classType != null; 090 091 v.defineClass(scriptDeclaration, 092 V1_6, 093 ACC_PUBLIC, 094 classType.getInternalName(), 095 null, 096 "java/lang/Object", 097 new String[0]); 098 } 099 100 @Override 101 protected void generateBody() { 102 genMembers(); 103 genFieldsForParameters(scriptDescriptor, v); 104 genConstructor(scriptDescriptor, context.getContextDescriptor(), v, 105 context.intoFunction(scriptDescriptor.getScriptCodeDescriptor())); 106 } 107 108 @Override 109 protected void generateKotlinAnnotation() { 110 // TODO 111 } 112 113 private void genConstructor( 114 @NotNull ScriptDescriptor scriptDescriptor, 115 @NotNull ClassDescriptor classDescriptorForScript, 116 @NotNull ClassBuilder classBuilder, 117 @NotNull final MethodContext methodContext 118 ) { 119 Type blockType = typeMapper.mapType(scriptDescriptor.getScriptCodeDescriptor().getReturnType()); 120 121 classBuilder.newField(null, ACC_PUBLIC | ACC_FINAL, ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 122 blockType.getDescriptor(), null, null); 123 124 JvmMethodSignature jvmSignature = typeMapper.mapScriptSignature(scriptDescriptor, context.getEarlierScripts()); 125 126 MethodVisitor mv = classBuilder.newMethod( 127 scriptDeclaration, ACC_PUBLIC, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(), 128 null, null); 129 130 mv.visitCode(); 131 132 final InstructionAdapter instructionAdapter = new InstructionAdapter(mv); 133 134 Type classType = bindingContext.get(ASM_TYPE, classDescriptorForScript); 135 assert classType != null; 136 137 instructionAdapter.load(0, classType); 138 instructionAdapter.invokespecial("java/lang/Object", "<init>", "()V"); 139 140 instructionAdapter.load(0, classType); 141 142 final FrameMap frameMap = methodContext.prepareFrame(typeMapper); 143 144 for (ScriptDescriptor importedScript : context.getEarlierScripts()) { 145 frameMap.enter(importedScript, OBJECT_TYPE); 146 } 147 148 Type[] argTypes = jvmSignature.getAsmMethod().getArgumentTypes(); 149 int add = 0; 150 151 for (int i = 0; i < scriptDescriptor.getScriptCodeDescriptor().getValueParameters().size(); i++) { 152 ValueParameterDescriptor parameter = scriptDescriptor.getScriptCodeDescriptor().getValueParameters().get(i); 153 frameMap.enter(parameter, argTypes[i + add]); 154 } 155 156 generateInitializers(new Function0<ExpressionCodegen>() { 157 @Override 158 public ExpressionCodegen invoke() { 159 return new ExpressionCodegen(instructionAdapter, frameMap, Type.VOID_TYPE, methodContext, state, ScriptCodegen.this); 160 } 161 }); 162 163 int offset = 1; 164 165 for (ScriptDescriptor earlierScript : context.getEarlierScripts()) { 166 Type earlierClassType = asmTypeForScriptDescriptor(bindingContext, earlierScript); 167 instructionAdapter.load(0, classType); 168 instructionAdapter.load(offset, earlierClassType); 169 offset += earlierClassType.getSize(); 170 instructionAdapter.putfield(classType.getInternalName(), context.getScriptFieldName(earlierScript), earlierClassType.getDescriptor()); 171 } 172 173 for (ValueParameterDescriptor parameter : scriptDescriptor.getScriptCodeDescriptor().getValueParameters()) { 174 Type parameterType = typeMapper.mapType(parameter.getType()); 175 instructionAdapter.load(0, classType); 176 instructionAdapter.load(offset, parameterType); 177 offset += parameterType.getSize(); 178 instructionAdapter.putfield(classType.getInternalName(), parameter.getName().getIdentifier(), parameterType.getDescriptor()); 179 } 180 181 StackValue stackValue = 182 new ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this).gen(scriptDeclaration.getBlockExpression()); 183 if (stackValue.type != Type.VOID_TYPE) { 184 stackValue.put(stackValue.type, instructionAdapter); 185 instructionAdapter.putfield(classType.getInternalName(), ScriptDescriptor.LAST_EXPRESSION_VALUE_FIELD_NAME, 186 blockType.getDescriptor()); 187 } 188 189 instructionAdapter.areturn(Type.VOID_TYPE); 190 mv.visitMaxs(-1, -1); 191 mv.visitEnd(); 192 } 193 194 private void genFieldsForParameters(@NotNull ScriptDescriptor script, @NotNull ClassBuilder classBuilder) { 195 for (ScriptDescriptor earlierScript : context.getEarlierScripts()) { 196 Type earlierClassName = asmTypeForScriptDescriptor(bindingContext, earlierScript); 197 int access = ACC_PRIVATE | ACC_FINAL; 198 classBuilder.newField(null, access, context.getScriptFieldName(earlierScript), earlierClassName.getDescriptor(), null, null); 199 } 200 201 for (ValueParameterDescriptor parameter : script.getScriptCodeDescriptor().getValueParameters()) { 202 Type parameterType = typeMapper.mapType(parameter); 203 int access = ACC_PUBLIC | ACC_FINAL; 204 classBuilder.newField(null, access, parameter.getName().getIdentifier(), parameterType.getDescriptor(), null, null); 205 } 206 } 207 208 private void genMembers() { 209 for (JetDeclaration declaration : scriptDeclaration.getDeclarations()) { 210 genFunctionOrProperty(declaration); 211 } 212 } 213 }