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