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