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