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 com.intellij.psi.tree.IElementType;
020 import org.jetbrains.annotations.Contract;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
024 import org.jetbrains.jet.codegen.state.GenerationState;
025 import org.jetbrains.jet.codegen.state.JetTypeMapper;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.psi.JetExpression;
028 import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage;
029 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
030 import org.jetbrains.jet.lang.resolve.java.JvmAbi;
031 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
032 import org.jetbrains.jet.lexer.JetTokens;
033 import org.jetbrains.org.objectweb.asm.Label;
034 import org.jetbrains.org.objectweb.asm.Type;
035 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
036 import org.jetbrains.org.objectweb.asm.commons.Method;
037
038 import java.util.List;
039
040 import static org.jetbrains.jet.codegen.AsmUtil.*;
041 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
042 import static org.jetbrains.org.objectweb.asm.Opcodes.*;
043
044 public abstract class StackValue {
045
046 private static final String NULLABLE_BYTE_TYPE_NAME = "java/lang/Byte";
047 private static final String NULLABLE_SHORT_TYPE_NAME = "java/lang/Short";
048 private static final String NULLABLE_LONG_TYPE_NAME = "java/lang/Long";
049
050 @NotNull
051 public final Type type;
052
053 protected StackValue(@NotNull Type type) {
054 this.type = type;
055 }
056
057 /**
058 * Put this value to the top of the stack.
059 */
060 public abstract void put(Type type, InstructionAdapter v);
061
062 /**
063 * This method is called to put the value on the top of the JVM stack if <code>depth</code> other values have been put on the
064 * JVM stack after this value was generated.
065 *
066 * @param type the type as which the value should be put
067 * @param v the visitor used to genClassOrObject the instructions
068 * @param depth the number of new values put onto the stack
069 */
070 protected void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
071 put(type, v);
072 }
073
074 /**
075 * Set this value from the top of the stack.
076 */
077 public void store(Type topOfStackType, InstructionAdapter v) {
078 throw new UnsupportedOperationException("cannot store to value " + this);
079 }
080
081 public void dupReceiver(InstructionAdapter v) {
082 }
083
084 public int receiverSize() {
085 return 0;
086 }
087
088 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
089 put(this.type, v);
090 coerceTo(Type.BOOLEAN_TYPE, v);
091 if (jumpIfFalse) {
092 v.ifeq(label);
093 }
094 else {
095 v.ifne(label);
096 }
097 }
098
099 public static Local local(int index, Type type) {
100 return new Local(index, type);
101 }
102
103 public static StackValue shared(int index, Type type) {
104 return new Shared(index, type);
105 }
106
107 public static StackValue onStack(Type type) {
108 return type == Type.VOID_TYPE ? none() : new OnStack(type);
109 }
110
111 public static StackValue constant(@Nullable Object value, Type type) {
112 return new Constant(value, type);
113 }
114
115 public static StackValue cmp(IElementType opToken, Type type) {
116 return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type) : new NumberCompare(opToken, type);
117 }
118
119 public static StackValue not(StackValue stackValue) {
120 return new Invert(stackValue);
121 }
122
123 @NotNull
124 public static StackValue arrayElement(Type type) {
125 return new ArrayElement(type);
126 }
127
128 @NotNull
129 public static StackValue collectionElement(
130 Type type,
131 ResolvedCall<FunctionDescriptor> getter,
132 ResolvedCall<FunctionDescriptor> setter,
133 ExpressionCodegen codegen,
134 GenerationState state
135 ) {
136 return new CollectionElement(type, getter, setter, codegen, state);
137 }
138
139 @NotNull
140 public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic) {
141 return new Field(type, owner, name, isStatic);
142 }
143
144 @NotNull
145 public static Property property(
146 @NotNull PropertyDescriptor descriptor,
147 @NotNull Type methodOwner,
148 @NotNull Type type,
149 boolean isStatic,
150 @Nullable String fieldName,
151 @Nullable CallableMethod getter,
152 @Nullable CallableMethod setter,
153 GenerationState state
154 ) {
155 return new Property(descriptor, methodOwner, getter, setter, isStatic, fieldName, type, state);
156 }
157
158 @NotNull
159 public static StackValue expression(Type type, JetExpression expression, ExpressionCodegen generator) {
160 return new Expression(type, expression, generator);
161 }
162
163 private static void box(Type type, Type toType, InstructionAdapter v) {
164 if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
165 v.cast(type, Type.BYTE_TYPE);
166 v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
167 }
168 else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
169 v.cast(type, Type.SHORT_TYPE);
170 v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
171 }
172 else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
173 v.cast(type, Type.LONG_TYPE);
174 v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
175 }
176 else if (type == Type.INT_TYPE) {
177 v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
178 }
179 else if (type == Type.BOOLEAN_TYPE) {
180 v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
181 }
182 else if (type == Type.CHAR_TYPE) {
183 v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
184 }
185 else if (type == Type.FLOAT_TYPE) {
186 v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
187 }
188 else if (type == Type.DOUBLE_TYPE) {
189 v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
190 }
191 }
192
193 private static void unbox(Type type, InstructionAdapter v) {
194 if (type == Type.INT_TYPE) {
195 v.invokevirtual("java/lang/Number", "intValue", "()I", false);
196 }
197 else if (type == Type.BOOLEAN_TYPE) {
198 v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
199 }
200 else if (type == Type.CHAR_TYPE) {
201 v.invokevirtual("java/lang/Character", "charValue", "()C", false);
202 }
203 else if (type == Type.SHORT_TYPE) {
204 v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
205 }
206 else if (type == Type.LONG_TYPE) {
207 v.invokevirtual("java/lang/Number", "longValue", "()J", false);
208 }
209 else if (type == Type.BYTE_TYPE) {
210 v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
211 }
212 else if (type == Type.FLOAT_TYPE) {
213 v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
214 }
215 else if (type == Type.DOUBLE_TYPE) {
216 v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
217 }
218 }
219
220 protected void coerceTo(Type toType, InstructionAdapter v) {
221 coerce(this.type, toType, v);
222 }
223
224 protected void coerceFrom(Type topOfStackType, InstructionAdapter v) {
225 coerce(topOfStackType, this.type, v);
226 }
227
228 public static void coerce(Type fromType, Type toType, InstructionAdapter v) {
229 if (toType.equals(fromType)) return;
230
231 if (toType.getSort() == Type.VOID) {
232 pop(v, fromType);
233 }
234 else if (fromType.getSort() == Type.VOID) {
235 if (toType.equals(UNIT_TYPE) || toType.equals(OBJECT_TYPE)) {
236 putUnitInstance(v);
237 }
238 else if (toType.getSort() == Type.OBJECT || toType.getSort() == Type.ARRAY) {
239 v.aconst(null);
240 }
241 else {
242 pushDefaultPrimitiveValueOnStack(toType, v);
243 }
244 }
245 else if (toType.equals(UNIT_TYPE)) {
246 if (fromType.equals(getType(Object.class))) {
247 v.checkcast(UNIT_TYPE);
248 }
249 else if (!fromType.equals(getType(Void.class))) {
250 pop(v, fromType);
251 putUnitInstance(v);
252 }
253 }
254 else if (toType.getSort() == Type.ARRAY) {
255 v.checkcast(toType);
256 }
257 else if (toType.getSort() == Type.OBJECT) {
258 if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
259 if (!toType.equals(OBJECT_TYPE)) {
260 v.checkcast(toType);
261 }
262 }
263 else {
264 box(fromType, toType, v);
265 }
266 }
267 else if (fromType.getSort() == Type.OBJECT) {
268 if (fromType.equals(getType(Boolean.class)) || fromType.equals(getType(Character.class))) {
269 unbox(unboxType(fromType), v);
270 coerce(unboxType(fromType), toType, v);
271 }
272 else {
273 if (toType.getSort() == Type.BOOLEAN || toType.getSort() == Type.CHAR) {
274 coerce(fromType, boxType(toType), v);
275 }
276 else {
277 coerce(fromType, getType(Number.class), v);
278 }
279 unbox(toType, v);
280 }
281 }
282 else {
283 v.cast(fromType, toType);
284 }
285 }
286
287 public static void putUnitInstance(InstructionAdapter v) {
288 v.visitFieldInsn(GETSTATIC, UNIT_TYPE.getInternalName(), JvmAbi.INSTANCE_FIELD, UNIT_TYPE.getDescriptor());
289 }
290
291 protected void putAsBoolean(InstructionAdapter v) {
292 Label ifTrue = new Label();
293 Label end = new Label();
294 condJump(ifTrue, false, v);
295 v.iconst(0);
296 v.goTo(end);
297 v.mark(ifTrue);
298 v.iconst(1);
299 v.mark(end);
300 }
301
302 public static StackValue none() {
303 return None.INSTANCE;
304 }
305
306 public static StackValue fieldForSharedVar(Type localType, Type classType, String fieldName) {
307 return new FieldForSharedVar(localType, classType, fieldName);
308 }
309
310 public static StackValue composed(StackValue prefix, StackValue suffix) {
311 return new Composed(prefix, suffix);
312 }
313
314 public static StackValue thisOrOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean isExplicit) {
315 // Coerce this/super for traits to support traits with required classes.
316 // Coerce explicit 'this' for the case when it is smartcasted.
317 // Do not coerce for other classes due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
318 boolean coerceType = descriptor.getKind() == ClassKind.TRAIT || (isExplicit && !isSuper);
319 return new ThisOuter(codegen, descriptor, isSuper, coerceType);
320 }
321
322 public static StackValue postIncrement(int index, int increment) {
323 return new PostIncrement(index, increment);
324 }
325
326 public static StackValue preIncrement(int index, int increment) {
327 return new PreIncrement(index, increment);
328 }
329
330 public static StackValue receiver(
331 ResolvedCall<?> resolvedCall,
332 StackValue receiver,
333 ExpressionCodegen codegen,
334 @Nullable CallableMethod callableMethod
335 ) {
336 if (resolvedCall.getDispatchReceiver().exists() || resolvedCall.getExtensionReceiver().exists() || isLocalFunCall(callableMethod)) {
337 return new CallReceiver(resolvedCall, receiver, codegen, callableMethod, true);
338 }
339 return receiver;
340 }
341
342 @Contract("null -> false")
343 private static boolean isLocalFunCall(@Nullable CallableMethod callableMethod) {
344 return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
345 }
346
347 public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
348 if (receiverWithParameter instanceof CallReceiver) {
349 CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
350 return new CallReceiver(callReceiver.resolvedCall, callReceiver.receiver,
351 callReceiver.codegen, callReceiver.callableMethod, false);
352 }
353 return receiverWithParameter;
354 }
355
356 public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
357 FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper);
358 return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), true);
359 }
360
361 public static boolean couldSkipReceiverOnStaticCall(StackValue value) {
362 return value instanceof Local || value instanceof Constant;
363 }
364
365 private static class None extends StackValue {
366 public static final None INSTANCE = new None();
367
368 private None() {
369 super(Type.VOID_TYPE);
370 }
371
372 @Override
373 public void put(Type type, InstructionAdapter v) {
374 coerceTo(type, v);
375 }
376 }
377
378 public static class Local extends StackValue {
379 public final int index;
380
381 private Local(int index, Type type) {
382 super(type);
383 this.index = index;
384
385 if (index < 0) {
386 throw new IllegalStateException("local variable index must be non-negative");
387 }
388 }
389
390 @Override
391 public void put(Type type, InstructionAdapter v) {
392 v.load(index, this.type);
393 coerceTo(type, v);
394 // TODO unbox
395 }
396
397 @Override
398 public void store(Type topOfStackType, InstructionAdapter v) {
399 coerceFrom(topOfStackType, v);
400 v.store(index, this.type);
401 }
402 }
403
404 public static class OnStack extends StackValue {
405 public OnStack(Type type) {
406 super(type);
407 }
408
409 @Override
410 public void put(Type type, InstructionAdapter v) {
411 coerceTo(type, v);
412 }
413
414 @Override
415 public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
416 if (depth == 0) {
417 put(type, v);
418 }
419 else if (depth == 1) {
420 int size = this.type.getSize();
421 if (size == 1) {
422 v.swap();
423 } else if (size == 2) {
424 v.dupX2();
425 v.pop();
426 } else {
427 throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
428 }
429
430 coerceTo(type, v);
431 }
432 else {
433 throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
434 }
435 }
436 }
437
438 public static class Constant extends StackValue {
439 @Nullable
440 private final Object value;
441
442 public Constant(@Nullable Object value, Type type) {
443 super(type);
444 this.value = value;
445 }
446
447 @Override
448 public void put(Type type, InstructionAdapter v) {
449 if (value instanceof Integer) {
450 v.iconst((Integer) value);
451 }
452 else if (value instanceof Long) {
453 v.lconst((Long) value);
454 }
455 else if (value instanceof Float) {
456 v.fconst((Float) value);
457 }
458 else if (value instanceof Double) {
459 v.dconst((Double) value);
460 }
461 else {
462 v.aconst(value);
463 }
464
465 coerceTo(type, v);
466 }
467
468 @Override
469 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
470 if (value instanceof Boolean) {
471 boolean boolValue = (Boolean) value;
472 if (boolValue ^ jumpIfFalse) {
473 v.goTo(label);
474 }
475 }
476 else {
477 throw new UnsupportedOperationException("don't know how to generate this condjump");
478 }
479 }
480 }
481
482 private static class NumberCompare extends StackValue {
483 protected final IElementType opToken;
484 private final Type operandType;
485
486 public NumberCompare(IElementType opToken, Type operandType) {
487 super(Type.BOOLEAN_TYPE);
488 this.opToken = opToken;
489 this.operandType = operandType;
490 }
491
492 @Override
493 public void put(Type type, InstructionAdapter v) {
494 putAsBoolean(v);
495 coerceTo(type, v);
496 }
497
498 @Override
499 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
500 int opcode;
501 if (opToken == JetTokens.EQEQ) {
502 opcode = jumpIfFalse ? IFNE : IFEQ;
503 }
504 else if (opToken == JetTokens.EXCLEQ) {
505 opcode = jumpIfFalse ? IFEQ : IFNE;
506 }
507 else if (opToken == JetTokens.GT) {
508 opcode = jumpIfFalse ? IFLE : IFGT;
509 }
510 else if (opToken == JetTokens.GTEQ) {
511 opcode = jumpIfFalse ? IFLT : IFGE;
512 }
513 else if (opToken == JetTokens.LT) {
514 opcode = jumpIfFalse ? IFGE : IFLT;
515 }
516 else if (opToken == JetTokens.LTEQ) {
517 opcode = jumpIfFalse ? IFGT : IFLE;
518 }
519 else {
520 throw new UnsupportedOperationException("don't know how to generate this condjump");
521 }
522 if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) {
523 if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
524 v.cmpl(operandType);
525 }
526 else {
527 v.cmpg(operandType);
528 }
529 }
530 else if (operandType == Type.LONG_TYPE) {
531 v.lcmp();
532 }
533 else {
534 opcode += (IF_ICMPEQ - IFEQ);
535 }
536 v.visitJumpInsn(opcode, label);
537 }
538 }
539
540 private static class ObjectCompare extends NumberCompare {
541 public ObjectCompare(IElementType opToken, Type operandType) {
542 super(opToken, operandType);
543 }
544
545 @Override
546 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
547 int opcode;
548 if (opToken == JetTokens.EQEQEQ) {
549 opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ;
550 }
551 else if (opToken == JetTokens.EXCLEQEQEQ) {
552 opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE;
553 }
554 else {
555 throw new UnsupportedOperationException("don't know how to generate this condjump");
556 }
557 v.visitJumpInsn(opcode, label);
558 }
559 }
560
561 private static class Invert extends StackValue {
562 private final StackValue myOperand;
563
564 private Invert(StackValue operand) {
565 super(Type.BOOLEAN_TYPE);
566 myOperand = operand;
567 if (myOperand.type != Type.BOOLEAN_TYPE) {
568 throw new UnsupportedOperationException("operand of ! must be boolean");
569 }
570 }
571
572 @Override
573 public void put(Type type, InstructionAdapter v) {
574 putAsBoolean(v);
575 coerceTo(type, v);
576 }
577
578 @Override
579 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
580 myOperand.condJump(label, !jumpIfFalse, v);
581 }
582 }
583
584 private static class ArrayElement extends StackValue {
585 public ArrayElement(Type type) {
586 super(type);
587 }
588
589 @Override
590 public void put(Type type, InstructionAdapter v) {
591 v.aload(this.type); // assumes array and index are on the stack
592 coerceTo(type, v);
593 }
594
595 @Override
596 public void store(Type topOfStackType, InstructionAdapter v) {
597 coerceFrom(topOfStackType, v);
598 v.astore(this.type);
599 }
600
601 @Override
602 public void dupReceiver(InstructionAdapter v) {
603 v.dup2(); // array and index
604 }
605
606 @Override
607 public int receiverSize() {
608 return 2;
609 }
610 }
611
612 private static class CollectionElement extends StackValue {
613 private final Callable getter;
614 private final Callable setter;
615 private final ExpressionCodegen codegen;
616 private final GenerationState state;
617 private final FrameMap frame;
618 private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
619 private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
620 private final FunctionDescriptor setterDescriptor;
621 private final FunctionDescriptor getterDescriptor;
622
623 public CollectionElement(
624 Type type,
625 ResolvedCall<FunctionDescriptor> resolvedGetCall,
626 ResolvedCall<FunctionDescriptor> resolvedSetCall,
627 ExpressionCodegen codegen,
628 GenerationState state
629 ) {
630 super(type);
631 this.resolvedGetCall = resolvedGetCall;
632 this.resolvedSetCall = resolvedSetCall;
633 this.state = state;
634 this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
635 this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor();
636 this.setter = resolvedSetCall == null ? null : codegen.resolveToCallable(setterDescriptor, false);
637 this.getter = resolvedGetCall == null ? null : codegen.resolveToCallable(getterDescriptor, false);
638 this.codegen = codegen;
639 this.frame = codegen.myFrameMap;
640 }
641
642 @Override
643 public void put(Type type, InstructionAdapter v) {
644 if (getter == null) {
645 throw new UnsupportedOperationException("no getter specified");
646 }
647 if (getter instanceof CallableMethod) {
648 ((CallableMethod) getter).invokeWithNotNullAssertion(v, state, resolvedGetCall);
649 }
650 else {
651 ((IntrinsicMethod) getter).generate(codegen, v, this.type, null, null, null);
652 }
653 coerceTo(type, v);
654 }
655
656 @Override
657 public void store(Type topOfStackType, InstructionAdapter v) {
658 if (setter == null) {
659 throw new UnsupportedOperationException("no setter specified");
660 }
661 if (setter instanceof CallableMethod) {
662 CallableMethod method = (CallableMethod) setter;
663 Method asmMethod = method.getAsmMethod();
664 Type[] argumentTypes = asmMethod.getArgumentTypes();
665 coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v);
666 method.invokeWithNotNullAssertion(v, state, resolvedSetCall);
667 Type returnType = asmMethod.getReturnType();
668 if (returnType != Type.VOID_TYPE) {
669 pop(v, returnType);
670 }
671 }
672 else {
673 //noinspection ConstantConditions
674 ((IntrinsicMethod) setter).generate(codegen, v, null, null, null, null);
675 }
676 }
677
678 @Override
679 public int receiverSize() {
680 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
681 return 2;
682 }
683 else {
684 return -1;
685 }
686 }
687
688 @Override
689 public void dupReceiver(InstructionAdapter v) {
690 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
691 v.dup2(); // collection and index
692 return;
693 }
694
695 FrameMap.Mark mark = frame.mark();
696
697 // indexes
698 List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
699 int firstParamIndex = -1;
700 for (int i = valueParameters.size() - 1; i >= 0; --i) {
701 Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType());
702 firstParamIndex = frame.enterTemp(type);
703 v.store(firstParamIndex, type);
704 }
705
706 ReceiverValue receiverParameter = resolvedGetCall.getExtensionReceiver();
707 int receiverIndex = -1;
708 if (receiverParameter.exists()) {
709 Type type = codegen.typeMapper.mapType(receiverParameter.getType());
710 receiverIndex = frame.enterTemp(type);
711 v.store(receiverIndex, type);
712 }
713
714 ReceiverValue dispatchReceiver = resolvedGetCall.getDispatchReceiver();
715 int thisIndex = -1;
716 if (dispatchReceiver.exists()) {
717 thisIndex = frame.enterTemp(OBJECT_TYPE);
718 v.store(thisIndex, OBJECT_TYPE);
719 }
720
721 // for setter
722
723 int realReceiverIndex;
724 Type realReceiverType;
725 if (receiverIndex != -1) {
726 realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
727 realReceiverIndex = receiverIndex;
728 }
729 else if (thisIndex != -1) {
730 realReceiverType = OBJECT_TYPE;
731 realReceiverIndex = thisIndex;
732 }
733 else {
734 throw new UnsupportedOperationException();
735 }
736
737 if (resolvedSetCall.getDispatchReceiver().exists()) {
738 if (resolvedSetCall.getExtensionReceiver().exists()) {
739 codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver(), OBJECT_TYPE);
740 }
741 v.load(realReceiverIndex, realReceiverType);
742 }
743 else {
744 if (resolvedSetCall.getExtensionReceiver().exists()) {
745 v.load(realReceiverIndex, realReceiverType);
746 }
747 else {
748 throw new UnsupportedOperationException();
749 }
750 }
751
752 int index = firstParamIndex;
753 for (ValueParameterDescriptor valueParameter : valueParameters) {
754 Type type = codegen.typeMapper.mapType(valueParameter.getType());
755 v.load(index, type);
756 index -= type.getSize();
757 }
758
759 // restoring original
760 if (thisIndex != -1) {
761 v.load(thisIndex, OBJECT_TYPE);
762 }
763
764 if (receiverIndex != -1) {
765 v.load(receiverIndex, realReceiverType);
766 }
767
768 index = firstParamIndex;
769 for (ValueParameterDescriptor valueParameter : valueParameters) {
770 Type type = codegen.typeMapper.mapType(valueParameter.getType());
771 v.load(index, type);
772 index -= type.getSize();
773 }
774
775 mark.dropTo();
776 }
777
778 private boolean isStandardStack(ResolvedCall<?> call, int valueParamsSize) {
779 if (call == null) {
780 return true;
781 }
782
783 List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
784 if (valueParameters.size() != valueParamsSize) {
785 return false;
786 }
787
788 for (ValueParameterDescriptor valueParameter : valueParameters) {
789 if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
790 return false;
791 }
792 }
793
794 if (call.getDispatchReceiver().exists()) {
795 if (call.getExtensionReceiver().exists()) {
796 return false;
797 }
798 }
799 else {
800 if (codegen.typeMapper.mapType(call.getResultingDescriptor().getExtensionReceiverParameter().getType())
801 .getSize() != 1) {
802 return false;
803 }
804 }
805
806 return true;
807 }
808 }
809
810
811 public static class Field extends StackValueWithSimpleReceiver {
812 public final Type owner;
813 public final String name;
814
815 public Field(Type type, Type owner, String name, boolean isStatic) {
816 super(type, isStatic);
817 this.owner = owner;
818 this.name = name;
819 }
820
821 @Override
822 public void put(Type type, InstructionAdapter v) {
823 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
824 coerceTo(type, v);
825 }
826
827 @Override
828 public void store(Type topOfStackType, InstructionAdapter v) {
829 coerceFrom(topOfStackType, v);
830 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
831 }
832 }
833
834 static class Property extends StackValueWithSimpleReceiver {
835 private final CallableMethod getter;
836 private final CallableMethod setter;
837 private final Type methodOwner;
838
839 private final PropertyDescriptor descriptor;
840 private final GenerationState state;
841
842 private final String fieldName;
843
844 public Property(
845 @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner,
846 @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStatic,
847 @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state
848 ) {
849 super(type, isStatic);
850 this.methodOwner = methodOwner;
851 this.getter = getter;
852 this.setter = setter;
853 this.descriptor = descriptor;
854 this.state = state;
855 this.fieldName = fieldName;
856 }
857
858 @Override
859 public void put(Type type, InstructionAdapter v) {
860 if (getter == null) {
861 assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
862 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor());
863 genNotNullAssertionForField(v, state, descriptor);
864 coerceTo(type, v);
865 }
866 else {
867 getter.invokeWithoutAssertions(v);
868 coerce(getter.getAsmMethod().getReturnType(), type, v);
869 }
870 }
871
872 @Override
873 public void store(Type topOfStackType, InstructionAdapter v) {
874 coerceFrom(topOfStackType, v);
875 if (setter == null) {
876 assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
877 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor());
878 }
879 else {
880 setter.invokeWithoutAssertions(v);
881 }
882 }
883
884 public boolean isPropertyWithBackingFieldInOuterClass() {
885 return descriptor instanceof AccessorForPropertyBackingFieldInOuterClass;
886 }
887 }
888
889 private static class Expression extends StackValue {
890 private final JetExpression expression;
891 private final ExpressionCodegen generator;
892
893 public Expression(Type type, JetExpression expression, ExpressionCodegen generator) {
894 super(type);
895 this.expression = expression;
896 this.generator = generator;
897 }
898
899 @Override
900 public void put(Type type, InstructionAdapter v) {
901 generator.gen(expression, type);
902 }
903 }
904
905 public static class Shared extends StackValue {
906 private final int index;
907 private boolean isReleaseOnPut = false;
908
909 public Shared(int index, Type type) {
910 super(type);
911 this.index = index;
912 }
913
914 public void releaseOnPut() {
915 isReleaseOnPut = true;
916 }
917
918 public int getIndex() {
919 return index;
920 }
921
922 @Override
923 public void put(Type type, InstructionAdapter v) {
924 v.load(index, OBJECT_TYPE);
925 Type refType = refType(this.type);
926 Type sharedType = sharedTypeForType(this.type);
927 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
928 coerceFrom(refType, v);
929 coerceTo(type, v);
930 if (isReleaseOnPut) {
931 v.aconst(null);
932 v.store(index, OBJECT_TYPE);
933 }
934 }
935
936 @Override
937 public void store(Type topOfStackType, InstructionAdapter v) {
938 coerceFrom(topOfStackType, v);
939 v.load(index, OBJECT_TYPE);
940 AsmUtil.swap(v, sharedTypeForType(this.type), topOfStackType);
941 Type refType = refType(this.type);
942 Type sharedType = sharedTypeForType(this.type);
943 v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
944 }
945 }
946
947 @NotNull
948 public static Type sharedTypeForType(@NotNull Type type) {
949 switch (type.getSort()) {
950 case Type.OBJECT:
951 case Type.ARRAY:
952 return OBJECT_REF_TYPE;
953 case Type.BYTE:
954 return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef");
955 case Type.SHORT:
956 return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef");
957 case Type.CHAR:
958 return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef");
959 case Type.INT:
960 return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef");
961 case Type.LONG:
962 return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef");
963 case Type.BOOLEAN:
964 return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef");
965 case Type.FLOAT:
966 return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef");
967 case Type.DOUBLE:
968 return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef");
969 default:
970 throw new UnsupportedOperationException();
971 }
972 }
973
974 public static Type refType(Type type) {
975 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
976 return OBJECT_TYPE;
977 }
978
979 return type;
980 }
981
982 static class FieldForSharedVar extends StackValueWithSimpleReceiver {
983 final Type owner;
984 final String name;
985
986 public FieldForSharedVar(Type type, Type owner, String name) {
987 super(type, false);
988 this.owner = owner;
989 this.name = name;
990 }
991
992 @Override
993 public void put(Type type, InstructionAdapter v) {
994 Type sharedType = sharedTypeForType(this.type);
995 Type refType = refType(this.type);
996 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
997 coerceFrom(refType, v);
998 coerceTo(type, v);
999 }
1000
1001 @Override
1002 public void store(Type topOfStackType, InstructionAdapter v) {
1003 coerceFrom(topOfStackType, v);
1004 v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
1005 }
1006 }
1007
1008 public static class Composed extends StackValue {
1009 public final StackValue prefix;
1010 public final StackValue suffix;
1011
1012 public Composed(StackValue prefix, StackValue suffix) {
1013 super(suffix.type);
1014 this.prefix = prefix;
1015 this.suffix = suffix;
1016 }
1017
1018 @Override
1019 public void put(Type type, InstructionAdapter v) {
1020 prefix.put(prefix.type, v);
1021 suffix.put(type, v);
1022 }
1023
1024 @Override
1025 public void store(Type topOfStackType, InstructionAdapter v) {
1026 prefix.put(OBJECT_TYPE, v);
1027 suffix.store(topOfStackType, v);
1028 }
1029 }
1030
1031 private static class ThisOuter extends StackValue {
1032 private final ExpressionCodegen codegen;
1033 private final ClassDescriptor descriptor;
1034 private final boolean isSuper;
1035 private final boolean coerceType;
1036
1037 public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) {
1038 super(OBJECT_TYPE);
1039 this.codegen = codegen;
1040 this.descriptor = descriptor;
1041 this.isSuper = isSuper;
1042 this.coerceType = coerceType;
1043 }
1044
1045 @Override
1046 public void put(Type type, InstructionAdapter v) {
1047 StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
1048 stackValue.put(coerceType ? type : stackValue.type, v);
1049 }
1050 }
1051
1052 private static class PostIncrement extends StackValue {
1053 private final int index;
1054 private final int increment;
1055
1056 public PostIncrement(int index, int increment) {
1057 super(Type.INT_TYPE);
1058 this.index = index;
1059 this.increment = increment;
1060 }
1061
1062 @Override
1063 public void put(Type type, InstructionAdapter v) {
1064 if (!type.equals(Type.VOID_TYPE)) {
1065 v.load(index, Type.INT_TYPE);
1066 coerceTo(type, v);
1067 }
1068 v.iinc(index, increment);
1069 }
1070 }
1071
1072 private static class PreIncrement extends StackValue {
1073 private final int index;
1074 private final int increment;
1075
1076 public PreIncrement(int index, int increment) {
1077 super(Type.INT_TYPE);
1078 this.index = index;
1079 this.increment = increment;
1080 }
1081
1082 @Override
1083 public void put(Type type, InstructionAdapter v) {
1084 v.iinc(index, increment);
1085 if (!type.equals(Type.VOID_TYPE)) {
1086 v.load(index, Type.INT_TYPE);
1087 coerceTo(type, v);
1088 }
1089 }
1090 }
1091
1092 public static class CallReceiver extends StackValue {
1093 private final ResolvedCall<?> resolvedCall;
1094 private final StackValue receiver;
1095 private final ExpressionCodegen codegen;
1096 private final CallableMethod callableMethod;
1097 private final boolean putReceiverArgumentOnStack;
1098
1099 public CallReceiver(
1100 @NotNull ResolvedCall<?> resolvedCall,
1101 @NotNull StackValue receiver,
1102 @NotNull ExpressionCodegen codegen,
1103 @Nullable CallableMethod callableMethod,
1104 boolean putReceiverArgumentOnStack
1105 ) {
1106 super(calcType(resolvedCall, codegen.typeMapper, callableMethod));
1107 this.resolvedCall = resolvedCall;
1108 this.receiver = receiver;
1109 this.codegen = codegen;
1110 this.callableMethod = callableMethod;
1111 this.putReceiverArgumentOnStack = putReceiverArgumentOnStack;
1112 }
1113
1114 private static Type calcType(
1115 @NotNull ResolvedCall<?> resolvedCall,
1116 @NotNull JetTypeMapper typeMapper,
1117 @Nullable CallableMethod callableMethod
1118 ) {
1119 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1120
1121 ReceiverParameterDescriptor dispatchReceiver = descriptor.getDispatchReceiverParameter();
1122 ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
1123
1124 if (extensionReceiver != null) {
1125 return callableMethod != null ? callableMethod.getReceiverClass() : typeMapper.mapType(extensionReceiver.getType());
1126 }
1127 else if (dispatchReceiver != null) {
1128 return callableMethod != null ? callableMethod.getThisType() : typeMapper.mapType(dispatchReceiver.getType());
1129 }
1130 else if (isLocalFunCall(callableMethod)) {
1131 return callableMethod.getGenerateCalleeType();
1132 }
1133
1134 return Type.VOID_TYPE;
1135 }
1136
1137 @Override
1138 public void put(Type type, InstructionAdapter v) {
1139 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1140
1141 ReceiverValue dispatchReceiver = resolvedCall.getDispatchReceiver();
1142 ReceiverValue extensionReceiver = resolvedCall.getExtensionReceiver();
1143 int depth = 0;
1144 if (dispatchReceiver.exists()) {
1145 if (!AnnotationsPackage.isPlatformStaticInObject(descriptor)) {
1146 if (extensionReceiver.exists()) {
1147 //noinspection ConstantConditions
1148 Type resultType =
1149 callableMethod != null ?
1150 callableMethod.getOwner() :
1151 codegen.typeMapper.mapType(descriptor.getDispatchReceiverParameter().getType());
1152
1153 codegen.generateReceiverValue(dispatchReceiver, resultType);
1154 }
1155 else {
1156 genReceiver(v, dispatchReceiver, type, null, 0);
1157 }
1158 depth = 1;
1159 }
1160 }
1161 else if (isLocalFunCall(callableMethod)) {
1162 assert receiver == none() || extensionReceiver.exists() :
1163 "Receiver should be present only for local extension function: " + callableMethod;
1164 StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal());
1165 assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
1166 value.put(callableMethod.getGenerateCalleeType(), v);
1167
1168 depth = 1;
1169 }
1170
1171 if (putReceiverArgumentOnStack && extensionReceiver.exists()) {
1172 genReceiver(v, extensionReceiver, type, descriptor.getExtensionReceiverParameter(), depth);
1173 }
1174 }
1175
1176 private void genReceiver(
1177 @NotNull InstructionAdapter v,
1178 @NotNull ReceiverValue receiverArgument,
1179 @NotNull Type type,
1180 @Nullable ReceiverParameterDescriptor receiverParameter,
1181 int depth
1182 ) {
1183 if (receiver == StackValue.none()) {
1184 if (receiverParameter != null) {
1185 Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType());
1186 codegen.generateReceiverValue(receiverArgument, receiverType);
1187 StackValue.onStack(receiverType).put(type, v);
1188 }
1189 else {
1190 codegen.generateReceiverValue(receiverArgument, type);
1191 }
1192 }
1193 else {
1194 receiver.moveToTopOfStack(type, v, depth);
1195 }
1196 }
1197 }
1198
1199 public abstract static class StackValueWithSimpleReceiver extends StackValue {
1200
1201 public final boolean isStatic;
1202
1203 public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) {
1204 super(type);
1205 this.isStatic = isStatic;
1206 }
1207
1208 @Override
1209 public void dupReceiver(InstructionAdapter v) {
1210 if (!isStatic) {
1211 v.dup();
1212 }
1213 }
1214
1215 @Override
1216 public int receiverSize() {
1217 return isStatic ? 0 : 1;
1218 }
1219 }
1220 }