ExpressionCodegen.java 38.1 KB
Newer Older
M
Maxim Shafirov 已提交
1 2
package org.jetbrains.jet.codegen;

3
import com.intellij.psi.*;
4
import com.intellij.psi.tree.IElementType;
D
Dmitry Jemerov 已提交
5
import org.jetbrains.annotations.Nullable;
M
Maxim Shafirov 已提交
6
import org.jetbrains.jet.lang.psi.*;
7
import org.jetbrains.jet.lang.resolve.BindingContext;
D
Dmitry Jemerov 已提交
8
import org.jetbrains.jet.lang.types.*;
D
Dmitry Jemerov 已提交
9
import org.jetbrains.jet.lexer.JetTokens;
10
import org.jetbrains.jet.resolve.DescriptorUtil;
M
Maxim Shafirov 已提交
11 12
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
D
Dmitry Jemerov 已提交
13
import org.objectweb.asm.Opcodes;
M
Maxim Shafirov 已提交
14 15
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
16
import org.objectweb.asm.commons.Method;
M
Maxim Shafirov 已提交
17 18 19 20 21 22 23 24

import java.util.List;
import java.util.Stack;

/**
 * @author max
 */
public class ExpressionCodegen extends JetVisitor {
D
Dmitry Jemerov 已提交
25 26 27
    private static final String CLASS_OBJECT = "java/lang/Object";
    private static final String CLASS_STRING = "java/lang/String";
    private static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder";
28
    private static final String CLASS_COMPARABLE = "java/lang/Comparable";
D
Dmitry Jemerov 已提交
29

D
Dmitry Jemerov 已提交
30 31
    private static final Type TYPE_OBJECT = Type.getObjectType(CLASS_OBJECT);

32 33
    private final Stack<Label> myContinueTargets = new Stack<Label>();
    private final Stack<Label> myBreakTargets = new Stack<Label>();
34
    private final Stack<StackValue> myStack = new Stack<StackValue>();
M
Maxim Shafirov 已提交
35 36

    private final InstructionAdapter v;
37
    private final FrameMap myMap;
38 39
    private final JetTypeMapper typeMapper;
    private final Type returnType;
40
    private final BindingContext bindingContext;
M
Maxim Shafirov 已提交
41

D
cleanup  
Dmitry Jemerov 已提交
42 43
    public ExpressionCodegen(MethodVisitor v, BindingContext bindingContext, FrameMap myMap, JetTypeMapper typeMapper,
                             Type returnType) {
44
        this.myMap = myMap;
45 46
        this.typeMapper = typeMapper;
        this.returnType = returnType;
M
Maxim Shafirov 已提交
47
        this.v = new InstructionAdapter(v);
48
        this.bindingContext = bindingContext;
M
Maxim Shafirov 已提交
49 50 51 52 53 54 55
    }

    private void gen(JetElement expr) {
        if (expr == null) throw new CompilationException();
        expr.accept(this);
    }

56 57 58 59 60 61 62 63 64
    private void gen(JetElement expr, Type type) {
        int oldStackDepth = myStack.size();
        gen(expr);
        if (myStack.size() == oldStackDepth+1) {
            StackValue value = myStack.pop();
            value.put(type, v);
        }
    }

65
    private void genToJVMStack(JetExpression expr) {
66 67 68
        gen(expr, expressionType(expr));
    }

69 70 71 72 73 74 75 76 77
    private StackValue generateIntermediateValue(final JetExpression baseExpression) {
        int oldStackSize = myStack.size();
        gen(baseExpression);
        if (myStack.size() != oldStackSize+1) {
            throw new UnsupportedOperationException("intermediate value expected");
        }
        return myStack.pop();
    }

M
Maxim Shafirov 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    @Override
    public void visitExpression(JetExpression expression) {
        throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
    }

    @Override
    public void visitParenthesizedExpression(JetParenthesizedExpression expression) {
        gen(expression.getExpression());
    }

    @Override
    public void visitAnnotatedExpression(JetAnnotatedExpression expression) {
        gen(expression.getBaseExpression());
    }

    @Override
    public void visitIfExpression(JetIfExpression expression) {
95 96
        JetType expressionType = bindingContext.getExpressionType(expression);
        Type asmType = typeMapper.mapType(expressionType);
97 98 99
        int oldStackDepth = myStack.size();
        gen(expression.getCondition());
        assert myStack.size() == oldStackDepth+1;
M
Maxim Shafirov 已提交
100 101 102 103 104 105 106 107 108

        JetExpression thenExpression = expression.getThen();
        JetExpression elseExpression = expression.getElse();

        if (thenExpression == null && elseExpression == null) {
            throw new CompilationException();
        }

        if (thenExpression == null) {
109
            generateSingleBranchIf(elseExpression, false);
M
Maxim Shafirov 已提交
110 111 112 113
            return;
        }

        if (elseExpression == null) {
114
            generateSingleBranchIf(thenExpression, true);
M
Maxim Shafirov 已提交
115 116 117 118 119
            return;
        }


        Label elseLabel = new Label();
120
        myStack.pop().condJump(elseLabel, true, v);   // == 0, i.e. false
M
Maxim Shafirov 已提交
121

122
        gen(thenExpression, asmType);
M
Maxim Shafirov 已提交
123 124 125 126 127

        Label endLabel = new Label();
        v.goTo(endLabel);
        v.mark(elseLabel);

128
        gen(elseExpression, asmType);
M
Maxim Shafirov 已提交
129 130

        v.mark(endLabel);
D
Dmitry Jemerov 已提交
131 132 133
        if (asmType != Type.VOID_TYPE) {
            myStack.push(StackValue.onStack(asmType));
        }
M
Maxim Shafirov 已提交
134 135 136 137 138
    }

    @Override
    public void visitWhileExpression(JetWhileExpression expression) {
        Label condition = new Label();
139
        myContinueTargets.push(condition);
M
Maxim Shafirov 已提交
140 141 142
        v.mark(condition);

        Label end = new Label();
143
        myBreakTargets.push(end);
M
Maxim Shafirov 已提交
144 145

        gen(expression.getCondition());
146
        myStack.pop().condJump(end, true, v);
M
Maxim Shafirov 已提交
147

148
        gen(expression.getBody(), Type.VOID_TYPE);
M
Maxim Shafirov 已提交
149 150 151
        v.goTo(condition);

        v.mark(end);
152 153
        myBreakTargets.pop();
        myContinueTargets.pop();
M
Maxim Shafirov 已提交
154 155 156 157 158 159
    }

    @Override
    public void visitDoWhileExpression(JetDoWhileExpression expression) {
        Label condition = new Label();
        v.mark(condition);
160
        myContinueTargets.push(condition);
M
Maxim Shafirov 已提交
161 162

        Label end = new Label();
163
        myBreakTargets.push(end);
M
Maxim Shafirov 已提交
164

165
        gen(expression.getBody(), Type.VOID_TYPE);
M
Maxim Shafirov 已提交
166 167

        gen(expression.getCondition());
168
        myStack.pop().condJump(condition, false, v);
M
Maxim Shafirov 已提交
169 170 171

        v.mark(end);

172 173
        myBreakTargets.pop();
        myContinueTargets.pop();
M
Maxim Shafirov 已提交
174 175
    }

176 177 178 179 180
    @Override
    public void visitForExpression(JetForExpression expression) {
        final JetExpression loopRange = expression.getLoopRange();
        Type loopRangeType = expressionType(loopRange);
        if (loopRangeType.getSort() == Type.ARRAY) {
181
            generateForInArray(expression, loopRangeType);
182 183 184 185 186 187
        }
        else {
            throw new UnsupportedOperationException("for/in loop currently only supported for arrays");
        }
    }

188 189
    private void generateForInArray(JetForExpression expression, Type loopRangeType) {
        final JetParameter loopParameter = expression.getLoopParameter();
190 191
        final VariableDescriptor parameterDescriptor = bindingContext.getParameterDescriptor(loopParameter);
        JetType paramType = parameterDescriptor.getOutType();
192 193
        Type asmParamType = typeMapper.mapType(paramType);

194 195 196 197
        int lengthVar = myMap.enterTemp();
        gen(expression.getLoopRange(), loopRangeType);
        v.arraylength();
        v.store(lengthVar, Type.INT_TYPE);
198 199 200
        int indexVar = myMap.enterTemp();
        v.aconst(0);
        v.store(indexVar, Type.INT_TYPE);
201
        myMap.enter(parameterDescriptor, asmParamType.getSize());
202 203

        Label condition = new Label();
204
        Label increment = new Label();
205 206
        Label end = new Label();
        v.mark(condition);
207 208
        myContinueTargets.push(increment);
        myBreakTargets.push(end);
209 210

        v.load(indexVar, Type.INT_TYPE);
211 212 213 214 215
        v.load(lengthVar, Type.INT_TYPE);
        v.ificmpge(end);

        gen(expression.getLoopRange(), loopRangeType);  // array
        v.load(indexVar, Type.INT_TYPE);
216 217
        v.aload(loopRangeType.getElementType());
        StackValue.onStack(loopRangeType.getElementType()).put(asmParamType, v);
218
        v.store(myMap.getIndex(parameterDescriptor), asmParamType);
219 220 221

        gen(expression.getBody(), Type.VOID_TYPE);

222 223
        v.mark(increment);
        v.iinc(indexVar, 1);
224
        v.goTo(condition);
225
        v.mark(end);
226

227 228 229
        final int paramIndex = myMap.leave(parameterDescriptor);
        v.visitLocalVariable(loopParameter.getName(), asmParamType.getDescriptor(), null, condition, end, paramIndex);
        myMap.leaveTemp();
230
        myMap.leaveTemp();
231 232
        myBreakTargets.pop();
        myContinueTargets.pop();
233 234
    }

M
Maxim Shafirov 已提交
235 236
    @Override
    public void visitBreakExpression(JetBreakExpression expression) {
A
Andrey Breslav 已提交
237
        JetSimpleNameExpression labelElement = expression.getTargetLabel();
M
Maxim Shafirov 已提交
238

239
        Label label = labelElement == null ? myBreakTargets.peek() : null; // TODO:
M
Maxim Shafirov 已提交
240 241 242 243 244 245 246 247

        v.goTo(label);
    }

    @Override
    public void visitContinueExpression(JetContinueExpression expression) {
        String labelName = expression.getLabelName();

248
        Label label = labelName == null ? myContinueTargets.peek() : null; // TODO:
M
Maxim Shafirov 已提交
249 250 251 252 253

        v.goTo(label);
    }

    private void generateSingleBranchIf(JetExpression expression, boolean inverse) {
254
        Label endLabel = new Label();
M
Maxim Shafirov 已提交
255

256
        myStack.pop().condJump(endLabel, inverse, v);
M
Maxim Shafirov 已提交
257

258
        gen(expression, Type.VOID_TYPE);
M
Maxim Shafirov 已提交
259

260
        v.mark(endLabel);
M
Maxim Shafirov 已提交
261 262 263 264
    }

    @Override
    public void visitConstantExpression(JetConstantExpression expression) {
D
Dmitry Jemerov 已提交
265
        myStack.push(StackValue.constant(expression.getValue(), expressionType(expression)));
M
Maxim Shafirov 已提交
266 267 268 269
    }

    @Override
    public void visitBlockExpression(JetBlockExpression expression) {
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
        List<JetElement> statements = expression.getStatements();
        generateBlock(statements);
    }

    @Override
    public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
        if (bindingContext.isBlock(expression)) {
            generateBlock(expression.getBody());
        }
        else {
            throw new UnsupportedOperationException("don't know how to generate non-block function literals");
        }
    }

    private void generateBlock(List<JetElement> statements) {
M
Maxim Shafirov 已提交
285 286 287 288 289
        Label blockStart = new Label();
        v.mark(blockStart);

        for (JetElement statement : statements) {
            if (statement instanceof JetProperty) {
A
Andrey Breslav 已提交
290
                final VariableDescriptor variableDescriptor = bindingContext.getVariableDescriptor((JetProperty) statement);
291 292
                final Type type = typeMapper.mapType(variableDescriptor.getOutType());
                myMap.enter(variableDescriptor, type.getSize());
M
Maxim Shafirov 已提交
293 294 295
            }
        }

296 297 298 299 300 301 302 303
        for (int i = 0, statementsSize = statements.size(); i < statementsSize; i++) {
            JetElement statement = statements.get(i);
            if (i == statements.size() - 1) {
                gen(statement);
            }
            else {
                gen(statement, Type.VOID_TYPE);
            }
M
Maxim Shafirov 已提交
304 305 306 307 308 309 310 311
        }

        Label blockEnd = new Label();
        v.mark(blockEnd);

        for (JetElement statement : statements) {
            if (statement instanceof JetProperty) {
                JetProperty var = (JetProperty) statement;
A
Andrey Breslav 已提交
312
                VariableDescriptor variableDescriptor = bindingContext.getVariableDescriptor(var);
313
                Type outType = typeMapper.mapType(variableDescriptor.getOutType());
314

315
                int index = myMap.leave(variableDescriptor);
316
                v.visitLocalVariable(var.getName(), outType.getDescriptor(), null, blockStart, blockEnd, index);
M
Maxim Shafirov 已提交
317 318 319 320
            }
        }
    }

D
Dmitry Jemerov 已提交
321 322 323 324
    @Override
    public void visitReturnExpression(JetReturnExpression expression) {
        final JetExpression returnedExpression = expression.getReturnedExpression();
        if (returnedExpression != null) {
325 326
            gen(returnedExpression, returnType);
            v.areturn(returnType);
D
Dmitry Jemerov 已提交
327 328 329 330 331 332
        }
        else {
            v.visitInsn(Opcodes.RETURN);
        }
    }

333 334 335 336 337 338 339 340
    public void returnTopOfStack() {
        if (myStack.size() > 0) {
            StackValue value = myStack.pop();
            value.put(returnType, v);
            v.areturn(returnType);
        }
    }

341
    @Override
342
    public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
A
Andrey Breslav 已提交
343
        final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression);
344
        if (descriptor instanceof VariableDescriptor) {
D
Dmitry Jemerov 已提交
345 346 347 348 349 350 351 352 353 354 355
            final DeclarationDescriptor container = descriptor.getContainingDeclaration();
            if (isClass(container, "Number")) {
                Type castType = getCastType(expression.getReferencedName());
                if (castType != null) {
                    final StackValue value = myStack.pop();
                    value.put(castType, v);
                    myStack.push(StackValue.onStack(castType));
                    return;
                }
            }
        }
D
Dmitry Jemerov 已提交
356 357 358
        PsiElement declaration = bindingContext.getDeclarationPsiElement(descriptor);
        if (declaration instanceof PsiField) {
            PsiField psiField = (PsiField) declaration;
359 360
            final String owner = JetTypeMapper.jvmName(psiField.getContainingClass());
            final Type fieldType = psiTypeToAsm(psiField.getType());
361 362
            final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
            if (!isStatic) {
363
                ensureReceiverOnStack(expression);
D
Dmitry Jemerov 已提交
364
            }
365
            myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
366 367
        }
        else {
D
Dmitry Jemerov 已提交
368 369
            int index = myMap.getIndex(descriptor);
            if (index >= 0) {
370
                final JetType outType = ((VariableDescriptor) descriptor).getOutType();
D
Dmitry Jemerov 已提交
371
                myStack.push(StackValue.local(index, typeMapper.mapType(outType)));
D
Dmitry Jemerov 已提交
372 373 374 375
            }
            else {
                throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
            }
376 377 378
        }
    }

D
Dmitry Jemerov 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    @Nullable
    private static Type getCastType(String castMethodName) {
        if ("dbl".equals(castMethodName)) {
            return Type.DOUBLE_TYPE;
        }
        if ("flt".equals(castMethodName)) {
            return Type.FLOAT_TYPE;
        }
        if ("lng".equals(castMethodName)) {
            return Type.LONG_TYPE;
        }
        if ("int".equals(castMethodName)) {
            return Type.INT_TYPE;
        }
        if ("chr".equals(castMethodName)) {
            return Type.CHAR_TYPE;
        }
        if ("sht".equals(castMethodName)) {
            return Type.SHORT_TYPE;
        }
        if ("byt".equals(castMethodName)) {
            return Type.BYTE_TYPE;
        }
        return null;
    }

405 406 407 408
    @Override
    public void visitCallExpression(JetCallExpression expression) {
        JetExpression callee = expression.getCalleeExpression();

409 410
        if (callee instanceof JetSimpleNameExpression) {
            DeclarationDescriptor funDescriptor = bindingContext.resolveReferenceExpression((JetSimpleNameExpression) callee);
411
            if (funDescriptor instanceof FunctionDescriptor) {
412 413
                final DeclarationDescriptor functionParent = funDescriptor.getContainingDeclaration();
                if (isNumberPrimitive(functionParent)) {
414 415 416 417 418 419 420 421
                    if (funDescriptor.getName().equals("inv")) {
                        final StackValue value = myStack.pop();  // HACK we rely on the dot reference handler to put it on the stack
                        final Type asmType = expressionType(expression);
                        value.put(asmType, v);
                        generateInv(asmType);
                        return;
                    }
                }
422

423
                ensureReceiverOnStack(expression);
424

425
                PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(funDescriptor);
426
                Method methodDescriptor;
427
                if (declarationPsiElement instanceof PsiMethod) {
428 429 430
                    PsiMethod psiMethod = (PsiMethod) declarationPsiElement;
                    methodDescriptor = getMethodDescriptor(psiMethod);
                    pushMethodArguments(expression, methodDescriptor);
431

432
                    final boolean isStatic = psiMethod.hasModifierProperty(PsiModifier.STATIC);
D
cleanup  
Dmitry Jemerov 已提交
433
                    v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL,
434 435 436
                            JetTypeMapper.jvmName(psiMethod.getContainingClass()),
                            methodDescriptor.getName(),
                            methodDescriptor.getDescriptor());
437
                }
438
                else {
439 440 441 442 443 444 445 446 447 448 449 450
                    if (functionParent instanceof NamespaceDescriptor && declarationPsiElement instanceof JetFunction) {
                        methodDescriptor = typeMapper.mapSignature((JetFunction) declarationPsiElement);
                        pushMethodArguments(expression, methodDescriptor);
                        final String owner = NamespaceCodegen.getJVMClassName(DescriptorUtil.getFQName(functionParent));
                        v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
                    }
                    else {
                        throw new UnsupportedOperationException("don't know how to generate call to " + declarationPsiElement);
                    }
                }
                if (methodDescriptor.getReturnType() != Type.VOID_TYPE) {
                    myStack.push(StackValue.onStack(methodDescriptor.getReturnType()));
451
                }
452 453 454 455 456 457 458 459 460 461
            }
            else {
                throw new CompilationException();
            }
        }
        else {
            throw new UnsupportedOperationException("Don't know how to generate a call");
        }
    }

462 463 464 465 466
    private void ensureReceiverOnStack(JetElement expression) {
        if (expression.getParent() instanceof JetDotQualifiedExpression) {
            final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
            if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
                // we have a receiver on stack
D
Dmitry Jemerov 已提交
467
                myStack.pop().put(TYPE_OBJECT, v);
468 469 470 471
            }
        }
    }

472 473
    private void pushMethodArguments(JetCall expression, Method method) {
        final Type[] argTypes = method.getArgumentTypes();
D
Dmitry Jemerov 已提交
474 475 476
        List<JetArgument> args = expression.getValueArguments();
        for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
            JetArgument arg = args.get(i);
477
            gen(arg.getArgumentExpression(), argTypes[i]);
D
Dmitry Jemerov 已提交
478
        }
479 480
    }

481
    private static Method getMethodDescriptor(PsiMethod method) {
D
Dmitry Jemerov 已提交
482
        Type returnType = method.isConstructor() ? Type.VOID_TYPE : psiTypeToAsm(method.getReturnType());
483 484 485 486 487
        PsiParameter[] parameters = method.getParameterList().getParameters();
        Type[] parameterTypes = new Type[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            parameterTypes[i] = psiTypeToAsm(parameters [i].getType());
        }
488
        return new Method(method.getName(), Type.getMethodDescriptor(returnType, parameterTypes));
489 490
    }

D
Dmitry Jemerov 已提交
491 492 493 494
    private Type expressionType(JetExpression expr) {
        return typeMapper.mapType(bindingContext.getExpressionType(expr));
    }

495 496 497 498 499
    private int indexOfLocal(JetReferenceExpression lhs) {
        final DeclarationDescriptor declarationDescriptor = bindingContext.resolveReferenceExpression(lhs);
        return myMap.getIndex(declarationDescriptor);
    }

500
    private static Type psiTypeToAsm(PsiType type) {
501 502 503 504
        if (type instanceof PsiPrimitiveType) {
            if (type == PsiType.VOID) {
                return Type.VOID_TYPE;
            }
505 506 507
            if (type == PsiType.INT) {
                return Type.INT_TYPE;
            }
508 509 510
            if (type == PsiType.LONG) {
                return Type.LONG_TYPE;
            }
511 512 513
            if (type == PsiType.BOOLEAN) {
                return Type.BOOLEAN_TYPE;
            }
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
            if (type == PsiType.BYTE) {
                return Type.BYTE_TYPE;
            }
            if (type == PsiType.SHORT) {
                return Type.SHORT_TYPE;
            }
            if (type == PsiType.CHAR) {
                return Type.CHAR_TYPE;
            }
            if (type == PsiType.FLOAT) {
                return Type.FLOAT_TYPE;
            }
            if (type == PsiType.DOUBLE) {
                return Type.DOUBLE_TYPE;
            }
529
        }
530 531 532 533 534
        if (type instanceof PsiClassType) {
            PsiClass psiClass = ((PsiClassType) type).resolve();
            if (psiClass == null) {
                throw new UnsupportedOperationException("unresolved PsiClassType: " + type);
            }
D
Dmitry Jemerov 已提交
535
            return JetTypeMapper.psiClassType(psiClass);
536
        }
D
Dmitry Jemerov 已提交
537
        throw new UnsupportedOperationException("don't know how to map type " + type + " to ASM");
538 539
    }

540
    @Override
541
    public void visitDotQualifiedExpression(JetDotQualifiedExpression expression) {
D
Dmitry Jemerov 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
        JetExpression receiver = expression.getReceiverExpression();
        if (!resolvesToClassOrPackage(receiver)) {
            gen(expression.getReceiverExpression());
        }
        gen(expression.getSelectorExpression());
    }

    private boolean resolvesToClassOrPackage(JetExpression receiver) {
        if (receiver instanceof JetReferenceExpression) {
            DeclarationDescriptor declaration = bindingContext.resolveReferenceExpression((JetReferenceExpression) receiver);
            PsiElement declarationElement = bindingContext.getDeclarationPsiElement(declaration);
            if (declarationElement instanceof PsiClass) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void visitSafeQualifiedExpression(JetSafeQualifiedExpression expression) {
562
        genToJVMStack(expression.getReceiverExpression());
D
Dmitry Jemerov 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575
        Label ifnull = new Label();
        Label end = new Label();
        v.dup();
        v.ifnull(ifnull);
        gen(expression.getSelectorExpression());
        v.goTo(end);
        v.mark(ifnull);
        // null is already on stack here after the dup
        JetType expressionType = bindingContext.getExpressionType(expression);
        if (expressionType.equals(JetStandardClasses.getUnitType())) {
            v.pop();
        }
        v.mark(end);
576
    }
577

D
Dmitry Jemerov 已提交
578 579
    @Override
    public void visitBinaryExpression(JetBinaryExpression expression) {
580 581
        final IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
        if (opToken == JetTokens.EQ) {
D
Dmitry Jemerov 已提交
582 583
            generateAssignmentExpression(expression);
        }
584
        else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
585 586
            generateAugmentedAssignment(expression);
        }
587 588 589 590 591 592
        else if (opToken == JetTokens.ANDAND) {
            generateBooleanAnd(expression);
        }
        else if (opToken == JetTokens.OROR) {
            generateBooleanOr(expression);
        }
D
Dmitry Jemerov 已提交
593 594
        else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ ||
                 opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
D
Dmitry Jemerov 已提交
595 596
            generateEquals(expression, opToken);
        }
597 598 599 600
        else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
                 opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
            generateCompareOp(expression, opToken, expressionType(expression.getLeft()));
        }
D
Dmitry Jemerov 已提交
601 602 603
        else if (opToken == JetTokens.ELVIS) {
            generateElvis(expression);
        }
604 605 606 607 608
        else {
            DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
            if (op instanceof FunctionDescriptor) {
                DeclarationDescriptor cls = op.getContainingDeclaration();
                if (isNumberPrimitive(cls)) {
609 610
                    int opcode = opcodeForMethod(op.getName());
                    generateBinaryOp(expression, (FunctionDescriptor) op, opcode);
611 612
                    return;
                }
D
Dmitry Jemerov 已提交
613 614 615 616
                else if (isClass(cls, "String") && op.getName().equals("plus")) {
                    generateConcatenation(expression);
                    return;
                }
D
Dmitry Jemerov 已提交
617
            }
618
            throw new UnsupportedOperationException("Don't know how to generate binary op " + expression);
619
        }
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
    }

    private void generateBooleanAnd(JetBinaryExpression expression) {
        gen(expression.getLeft(), Type.BOOLEAN_TYPE);
        Label ifFalse = new Label();
        v.ifeq(ifFalse);
        gen(expression.getRight(), Type.BOOLEAN_TYPE);
        Label end = new Label();
        v.goTo(end);
        v.mark(ifFalse);
        v.aconst(false);
        v.mark(end);
        myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE));
    }

    private void generateBooleanOr(JetBinaryExpression expression) {
        gen(expression.getLeft(), Type.BOOLEAN_TYPE);
        Label ifTrue = new Label();
        v.ifne(ifTrue);
        gen(expression.getRight(), Type.BOOLEAN_TYPE);
        Label end = new Label();
        v.goTo(end);
        v.mark(ifTrue);
        v.aconst(true);
        v.mark(end);
        myStack.push(StackValue.onStack(Type.BOOLEAN_TYPE));
D
Dmitry Jemerov 已提交
646
    }
647

D
Dmitry Jemerov 已提交
648 649 650 651 652 653 654 655 656
    private void generateEquals(JetBinaryExpression expression, IElementType opToken) {
        final Type leftType = expressionType(expression.getLeft());
        final Type rightType = expressionType(expression.getRight());
        if (isNumberPrimitive(leftType) && leftType == rightType) {
            generateCompareOp(expression, opToken, leftType);
        }
        else {
            gen(expression.getLeft(), leftType);
            gen(expression.getRight(), rightType);
D
Dmitry Jemerov 已提交
657 658
            if (opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
                myStack.push(StackValue.cmp(opToken, leftType));
D
Dmitry Jemerov 已提交
659 660
            }
            else {
D
Dmitry Jemerov 已提交
661
                generateNullSafeEquals(opToken);
D
Dmitry Jemerov 已提交
662 663 664 665
            }
        }
    }

D
Dmitry Jemerov 已提交
666 667 668 669 670 671
    private void generateNullSafeEquals(IElementType opToken) {
        v.dup2();   // left right left right
        Label rightNull = new Label();
        v.ifnull(rightNull);
        Label leftNull = new Label();
        v.ifnull(leftNull);
D
Dmitry Jemerov 已提交
672
        v.invokevirtual(CLASS_OBJECT, "equals", "(Ljava/lang/Object;)Z");
D
Dmitry Jemerov 已提交
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
        Label end = new Label();
        v.goTo(end);
        v.mark(rightNull);
        // left right left
        Label bothNull = new Label();
        v.ifnull(bothNull);
        v.mark(leftNull);
        v.pop2();
        v.aconst(Boolean.FALSE);
        v.goTo(end);
        v.mark(bothNull);
        v.pop2();
        v.aconst(Boolean.TRUE);
        v.mark(end);

        final StackValue onStack = StackValue.onStack(Type.BOOLEAN_TYPE);
        if (opToken == JetTokens.EXCLEQ) {
            myStack.push(StackValue.not(onStack));
        }
        else {
            myStack.push(onStack);
        }
    }

D
Dmitry Jemerov 已提交
697 698
    private void generateElvis(JetBinaryExpression expression) {
        final Type exprType = expressionType(expression);
699 700
        final Type leftType = expressionType(expression.getLeft());
        gen(expression.getLeft(), leftType);
D
Dmitry Jemerov 已提交
701 702 703 704
        v.dup();
        Label end = new Label();
        Label ifNull = new Label();
        v.ifnull(ifNull);
705
        StackValue.onStack(leftType).put(exprType, v);
D
Dmitry Jemerov 已提交
706 707 708 709 710 711 712 713
        v.goTo(end);
        v.mark(ifNull);
        v.pop();
        gen(expression.getRight(), exprType);
        v.mark(end);
        myStack.push(StackValue.onStack(exprType));
    }

D
Dmitry Jemerov 已提交
714 715 716 717 718
    private static boolean isNumberPrimitive(DeclarationDescriptor descriptor) {
        if (!(descriptor instanceof ClassDescriptor)) {
            return false;
        }
        String className = descriptor.getName();
D
Float  
Dmitry Jemerov 已提交
719
        return className.equals("Int") || className.equals("Long") || className.equals("Short") ||
D
Double  
Dmitry Jemerov 已提交
720 721
               className.equals("Byte") || className.equals("Char") || className.equals("Float") ||
               className.equals("Double");
D
Float  
Dmitry Jemerov 已提交
722 723
    }

D
Dmitry Jemerov 已提交
724 725 726 727 728 729 730 731
    private static boolean isClass(DeclarationDescriptor descriptor, String name) {
        if (!(descriptor instanceof ClassDescriptor)) {
            return false;
        }
        String className = descriptor.getName();
        return className.equals(name);
    }

D
Float  
Dmitry Jemerov 已提交
732
    private static boolean isNumberPrimitive(Type type) {
D
Dmitry Jemerov 已提交
733 734 735 736 737
        return isIntPrimitive(type) || type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE || type == Type.LONG_TYPE;
    }

    private static boolean isIntPrimitive(Type type) {
        return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE;
D
Dmitry Jemerov 已提交
738 739
    }

D
Dmitry Jemerov 已提交
740
    private static int opcodeForMethod(final String name) {
D
div/mod  
Dmitry Jemerov 已提交
741 742 743 744 745
        if (name.equals("plus")) return Opcodes.IADD;
        if (name.equals("minus")) return Opcodes.ISUB;
        if (name.equals("times")) return Opcodes.IMUL;
        if (name.equals("div")) return Opcodes.IDIV;
        if (name.equals("mod")) return Opcodes.IREM;
D
Dmitry Jemerov 已提交
746 747 748 749 750 751
        if (name.equals("shl")) return Opcodes.ISHL;
        if (name.equals("shr")) return Opcodes.ISHR;
        if (name.equals("ushr")) return Opcodes.IUSHR;
        if (name.equals("and")) return Opcodes.IAND;
        if (name.equals("or")) return Opcodes.IOR;
        if (name.equals("xor")) return Opcodes.IXOR;
D
Dmitry Jemerov 已提交
752 753 754
        throw new UnsupportedOperationException("Don't know how to generate binary op method " + name);
    }

755 756
    private void generateBinaryOp(JetBinaryExpression expression, FunctionDescriptor op, int opcode) {
        JetType returnType = op.getUnsubstitutedReturnType();
D
Dmitry Jemerov 已提交
757
        final Type asmType = typeMapper.mapType(returnType);
D
Double  
Dmitry Jemerov 已提交
758 759
        if (asmType == Type.INT_TYPE || asmType == Type.LONG_TYPE ||
            asmType == Type.FLOAT_TYPE || asmType == Type.DOUBLE_TYPE) {
D
Dmitry Jemerov 已提交
760 761 762 763
            gen(expression.getLeft(), asmType);
            gen(expression.getRight(), asmType);
            v.visitInsn(asmType.getOpcode(opcode));
            myStack.push(StackValue.onStack(asmType));
764 765 766 767 768 769
        }
        else {
            throw new UnsupportedOperationException("Don't know how to generate binary op with return type " + returnType);
        }
    }

770 771 772 773 774 775 776 777 778
    private void generateCompareOp(JetBinaryExpression expression, IElementType opToken, Type operandType) {
        gen(expression.getLeft(), operandType);
        gen(expression.getRight(), operandType);
        if (operandType.getSort() == Type.OBJECT) {
            v.invokeinterface(CLASS_COMPARABLE, "compareTo", "(Ljava/lang/Object;)I");
            v.aconst(0);
            operandType = Type.INT_TYPE;
        }
        myStack.push(StackValue.cmp(opToken, operandType));
779 780
    }

D
Dmitry Jemerov 已提交
781
    private void generateAssignmentExpression(JetBinaryExpression expression) {
782
        StackValue stackValue = generateIntermediateValue(expression.getLeft());
783
        genToJVMStack(expression.getRight());
784
        stackValue.store(v);
D
Dmitry Jemerov 已提交
785 786
    }

787
    private void generateAugmentedAssignment(JetBinaryExpression expression) {
788
        DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationReference());
789
        final JetExpression lhs = expression.getLeft();
790 791
        Type asmType = expressionType(lhs);
        StackValue value = generateIntermediateValue(lhs);
792
        value.dupReceiver(v);
793 794 795
        value.put(asmType, v);
        genToJVMStack(expression.getRight());
        v.visitInsn(asmType.getOpcode(opcodeForMethod(op.getName())));
796
        value.store(v);
797 798
    }

D
Dmitry Jemerov 已提交
799 800 801 802 803 804 805 806 807 808 809 810 811
    private void generateConcatenation(JetBinaryExpression expression) {
        Type type = Type.getObjectType(CLASS_STRING_BUILDER);
        v.anew(type);
        v.dup();
        Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
        v.invokespecial(CLASS_STRING_BUILDER, method.getName(), method.getDescriptor());
        invokeAppend(expression.getLeft());
        invokeAppend(expression.getRight());
        v.invokevirtual(CLASS_STRING_BUILDER, "toString", "()Ljava/lang/String;");
        myStack.push(StackValue.onStack(Type.getObjectType(CLASS_STRING)));
    }

    private void invokeAppend(final JetExpression expr) {
812 813 814 815 816 817 818 819
        if (expr instanceof JetBinaryExpression) {
            final JetBinaryExpression binaryExpression = (JetBinaryExpression) expr;
            if (binaryExpression.getOperationToken() == JetTokens.PLUS) {
                invokeAppend(binaryExpression.getLeft());
                invokeAppend(binaryExpression.getRight());
                return;
            }
        }
D
Dmitry Jemerov 已提交
820 821 822
        Type exprType = expressionType(expr);
        gen(expr, exprType);
        Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
D
Dmitry Jemerov 已提交
823
                new Type[] { exprType.getSort() == Type.OBJECT ? TYPE_OBJECT : exprType});
D
Dmitry Jemerov 已提交
824 825 826
        v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
    }

D
Dmitry Jemerov 已提交
827 828 829 830
    @Override
    public void visitPrefixExpression(JetPrefixExpression expression) {
        DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationSign());
        if (op instanceof FunctionDescriptor) {
831
            final Type asmType = expressionType(expression);
D
Dmitry Jemerov 已提交
832
            DeclarationDescriptor cls = op.getContainingDeclaration();
D
Dmitry Jemerov 已提交
833
            if (isNumberPrimitive(cls)) {
834 835
                if (generateUnaryOp(op, asmType, expression.getBaseExpression())) return;
            }
D
Dmitry Jemerov 已提交
836 837 838 839
            else if (isClass(cls, "Boolean") && op.getName().equals("not")) {
                generateNot(expression);
                return;
            }
840 841 842 843 844 845 846 847 848 849 850
        }
        throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
    }

    @Override
    public void visitPostfixExpression(JetPostfixExpression expression) {
        DeclarationDescriptor op = bindingContext.resolveReferenceExpression(expression.getOperationSign());
        if (op instanceof FunctionDescriptor) {
            final Type asmType = expressionType(expression);
            DeclarationDescriptor cls = op.getContainingDeclaration();
            if (isNumberPrimitive(cls) && (op.getName().equals("inc") || op.getName().equals("dec"))) {
851 852 853 854 855 856
                if (bindingContext.isStatement(expression)) {
                    generateIncrement(op, asmType, expression.getBaseExpression());
                }
                else {
                    int oldStackSize = myStack.size();
                    gen(expression.getBaseExpression(), asmType);
D
Dmitry Jemerov 已提交
857
                    generateIncrement(op, asmType, expression.getBaseExpression());
858 859 860
                    myStack.push(StackValue.onStack(asmType));
                    assert myStack.size() == oldStackSize+1;
                }
861
                return;
D
Dmitry Jemerov 已提交
862 863 864 865 866
            }
        }
        throw new UnsupportedOperationException("Don't know how to generate this prefix expression");
    }

867
    private boolean generateUnaryOp(DeclarationDescriptor op, Type asmType, final JetExpression operand) {
D
Dmitry Jemerov 已提交
868 869 870 871 872 873 874
        if (op.getName().equals("minus")) {
            gen(operand, asmType);
            v.neg(asmType);
            myStack.push(StackValue.onStack(asmType));
            return true;
        }
        else if (op.getName().equals("inc") || op.getName().equals("dec")) {
875
            myStack.push(generateIncrement(op, asmType, operand));
876 877 878 879 880
            return true;
        }
        return false;
    }

D
Dmitry Jemerov 已提交
881
    private void generateNot(JetPrefixExpression expression) {
882 883
        final StackValue stackValue = generateIntermediateValue(expression.getBaseExpression());
        myStack.push(StackValue.not(stackValue));
D
Dmitry Jemerov 已提交
884 885
    }

886
    private StackValue generateIncrement(DeclarationDescriptor op, Type asmType, JetExpression operand) {
887
        int increment = op.getName().equals("inc") ? 1 : -1;
888 889 890 891 892 893 894 895 896
        if (operand instanceof JetReferenceExpression) {
            final int index = indexOfLocal((JetReferenceExpression) operand);
            if (index < 0) {
                throw new UnsupportedOperationException("don't know how to increment or decrement something which is not a local var");
            }
            if (isIntPrimitive(asmType)) {
                v.iinc(index, increment);
                return StackValue.local(index, asmType);
            }
897
        }
898
        StackValue value = generateIntermediateValue(operand);
899
        value.dupReceiver(v);
900 901 902 903 904 905 906 907 908
        value.put(asmType, v);
        if (asmType == Type.LONG_TYPE) {
            v.aconst(Long.valueOf(increment));
        }
        else if (asmType == Type.FLOAT_TYPE) {
            v.aconst(Float.valueOf(increment));
        }
        else if (asmType == Type.DOUBLE_TYPE) {
            v.aconst(Double.valueOf(increment));
909 910
        }
        else {
911
            v.aconst(increment);
D
Dmitry Jemerov 已提交
912
        }
913
        v.add(asmType);
914
        value.store(v);
915
        return value;
D
Dmitry Jemerov 已提交
916 917
    }

918 919 920 921 922 923
    private void generateInv(Type asmType) {
        v.aconst(-1);
        v.xor(asmType);
        myStack.push(StackValue.onStack(asmType));
    }

M
Maxim Shafirov 已提交
924 925
    @Override
    public void visitProperty(JetProperty property) {
A
Andrey Breslav 已提交
926
        VariableDescriptor variableDescriptor = bindingContext.getVariableDescriptor(property);
927
        int index = myMap.getIndex(variableDescriptor);
M
Maxim Shafirov 已提交
928 929 930 931 932

        assert index >= 0;

        JetExpression initializer = property.getInitializer();
        if (initializer != null) {
933
            Type type = typeMapper.mapType(variableDescriptor.getOutType());
934 935
            gen(initializer, type);
            v.store(index, type);
M
Maxim Shafirov 已提交
936 937 938
        }
    }

D
Dmitry Jemerov 已提交
939 940 941 942 943 944 945 946 947 948 949
    @Override
    public void visitNewExpression(JetNewExpression expression) {
        final JetUserType constructorType = (JetUserType) expression.getTypeReference().getTypeElement();
        final JetSimpleNameExpression constructorReference = constructorType.getReferenceExpression();
        final PsiElement declaration = bindingContext.getDeclarationPsiElement(bindingContext.resolveReferenceExpression(constructorReference));
        if (declaration instanceof PsiMethod) {
            final PsiMethod constructor = (PsiMethod) declaration;
            PsiClass javaClass = constructor.getContainingClass();
            Type type = JetTypeMapper.psiClassType(javaClass);
            v.anew(type);
            v.dup();
950 951 952
            final Method constructorDescriptor = getMethodDescriptor(constructor);
            pushMethodArguments(expression, constructorDescriptor);
            v.invokespecial(JetTypeMapper.jvmName(javaClass), "<init>", constructorDescriptor.getDescriptor());
D
Dmitry Jemerov 已提交
953 954 955 956 957 958 959
            myStack.push(StackValue.onStack(type));
            return;
        }

        throw new UnsupportedOperationException("don't know how to generate this new expression");
    }

960 961 962 963 964 965 966 967
    @Override
    public void visitArrayAccessExpression(JetArrayAccessExpression expression) {
        final JetExpression array = expression.getArrayExpression();
        final Type arrayType = expressionType(array);
        if (arrayType.getSort() == Type.ARRAY) {
            gen(array, arrayType);
            generateArrayIndex(expression);
            final Type elementType = arrayType.getElementType();
968
            myStack.push(StackValue.arrayElement(elementType));
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
        }
        else {
            throw new UnsupportedOperationException("array access to non-Java arrays is not supported");
        }
    }

    private void generateArrayIndex(JetArrayAccessExpression expression) {
        final List<JetExpression> indices = expression.getIndexExpressions();
        if (indices.size() != 1) {
            throw new UnsupportedOperationException("array access with more than one index is not supported");
        }
        if (!expressionType(indices.get(0)).equals(Type.INT_TYPE)) {
            throw new UnsupportedOperationException("array access with non-integer is not supported");
        }
        gen(indices.get(0), Type.INT_TYPE);
    }

M
Maxim Shafirov 已提交
986 987 988
    private static class CompilationException extends RuntimeException {
    }
}