1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dexgen.rop.code;
18
19import com.android.dexgen.rop.cst.Constant;
20import com.android.dexgen.rop.type.StdTypeList;
21import com.android.dexgen.rop.type.Type;
22import com.android.dexgen.rop.type.TypeBearer;
23import com.android.dexgen.rop.type.TypeList;
24
25/**
26 * Plain instruction, which has no embedded data and which cannot possibly
27 * throw an exception.
28 */
29public final class PlainInsn
30        extends Insn {
31    /**
32     * Constructs an instance.
33     *
34     * @param opcode {@code non-null;} the opcode
35     * @param position {@code non-null;} source position
36     * @param result {@code null-ok;} spec for the result, if any
37     * @param sources {@code non-null;} specs for all the sources
38     */
39    public PlainInsn(Rop opcode, SourcePosition position,
40                     RegisterSpec result, RegisterSpecList sources) {
41        super(opcode, position, result, sources);
42
43        switch (opcode.getBranchingness()) {
44            case Rop.BRANCH_SWITCH:
45            case Rop.BRANCH_THROW: {
46                throw new IllegalArgumentException("bogus branchingness");
47            }
48        }
49
50        if (result != null && opcode.getBranchingness() != Rop.BRANCH_NONE) {
51            // move-result-pseudo is required here
52            throw new IllegalArgumentException
53                    ("can't mix branchingness with result");
54        }
55    }
56
57    /**
58     * Constructs a single-source instance.
59     *
60     * @param opcode {@code non-null;} the opcode
61     * @param position {@code non-null;} source position
62     * @param result {@code null-ok;} spec for the result, if any
63     * @param source {@code non-null;} spec for the source
64     */
65    public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
66                     RegisterSpec source) {
67        this(opcode, position, result, RegisterSpecList.make(source));
68    }
69
70    /** {@inheritDoc} */
71    @Override
72    public TypeList getCatches() {
73        return StdTypeList.EMPTY;
74    }
75
76    /** {@inheritDoc} */
77    @Override
78    public void accept(Visitor visitor) {
79        visitor.visitPlainInsn(this);
80    }
81
82    /** {@inheritDoc} */
83    @Override
84    public Insn withAddedCatch(Type type) {
85        throw new UnsupportedOperationException("unsupported");
86    }
87
88    /** {@inheritDoc} */
89    @Override
90    public Insn withRegisterOffset(int delta) {
91        return new PlainInsn(getOpcode(), getPosition(),
92                             getResult().withOffset(delta),
93                             getSources().withOffset(delta));
94    }
95
96    /** {@inheritDoc} */
97    @Override
98    public Insn withLastSourceLiteral() {
99        RegisterSpecList sources = getSources();
100        int szSources = sources.size();
101
102        if (szSources == 0) {
103            return this;
104        }
105
106        TypeBearer lastType = sources.get(szSources - 1).getTypeBearer();
107
108        if (!lastType.isConstant()) {
109            return this;
110        }
111
112        Constant cst = (Constant) lastType;
113
114        RegisterSpecList newSources = sources.withoutLast();
115
116        Rop newRop;
117        try {
118            newRop = Rops.ropFor(getOpcode().getOpcode(),
119                    getResult(), newSources, (Constant)lastType);
120        } catch (IllegalArgumentException ex) {
121            // There's no rop for this case
122            return this;
123        }
124
125        return new PlainCstInsn(newRop, getPosition(),
126                getResult(), newSources, cst);
127    }
128
129
130    /** {@inheritDoc} */
131    @Override
132    public Insn withNewRegisters(RegisterSpec result,
133            RegisterSpecList sources) {
134
135        return new PlainInsn(getOpcode(), getPosition(),
136                             result,
137                             sources);
138
139    }
140}
141