1/* libs/graphics/animator/SkScriptDecompile.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkScript2.h"
19
20#ifdef SK_DEBUG
21
22#define TypeOpName(op) {SkScriptEngine2::op, #op }
23
24static const struct OpName {
25    SkScriptEngine2::TypeOp fOp;
26    const char* fName;
27} gOpNames[] = {
28    TypeOpName(kNop), // should never get generated
29    TypeOpName(kAccumulatorPop),
30    TypeOpName(kAccumulatorPush),
31    TypeOpName(kAddInt),
32    TypeOpName(kAddScalar),
33    TypeOpName(kAddString), // string concat
34    TypeOpName(kArrayIndex),
35    TypeOpName(kArrayParam),
36    TypeOpName(kArrayToken),
37    TypeOpName(kBitAndInt),
38    TypeOpName(kBitNotInt),
39    TypeOpName(kBitOrInt),
40    TypeOpName(kBoxToken),
41    TypeOpName(kCallback),
42    TypeOpName(kDivideInt),
43    TypeOpName(kDivideScalar),
44    TypeOpName(kDotOperator),
45    TypeOpName(kElseOp),
46    TypeOpName(kEnd),
47    TypeOpName(kEqualInt),
48    TypeOpName(kEqualScalar),
49    TypeOpName(kEqualString),
50    TypeOpName(kFunctionCall),
51    TypeOpName(kFlipOpsOp),
52    TypeOpName(kFunctionToken),
53    TypeOpName(kGreaterEqualInt),
54    TypeOpName(kGreaterEqualScalar),
55    TypeOpName(kGreaterEqualString),
56    TypeOpName(kIfOp),
57    TypeOpName(kIntToScalar),
58    TypeOpName(kIntToScalar2),
59    TypeOpName(kIntToString),
60    TypeOpName(kIntToString2),
61    TypeOpName(kIntegerAccumulator),
62    TypeOpName(kIntegerOperand),
63    TypeOpName(kLogicalAndInt),
64    TypeOpName(kLogicalNotInt),
65    TypeOpName(kLogicalOrInt),
66    TypeOpName(kMemberOp),
67    TypeOpName(kMinusInt),
68    TypeOpName(kMinusScalar),
69    TypeOpName(kModuloInt),
70    TypeOpName(kModuloScalar),
71    TypeOpName(kMultiplyInt),
72    TypeOpName(kMultiplyScalar),
73    TypeOpName(kPropertyOp),
74    TypeOpName(kScalarAccumulator),
75    TypeOpName(kScalarOperand),
76    TypeOpName(kScalarToInt),
77    TypeOpName(kScalarToInt2),
78    TypeOpName(kScalarToString),
79    TypeOpName(kScalarToString2),
80    TypeOpName(kShiftLeftInt),
81    TypeOpName(kShiftRightInt), // signed
82    TypeOpName(kStringAccumulator),
83    TypeOpName(kStringOperand),
84    TypeOpName(kStringToInt),
85    TypeOpName(kStringToScalar),
86    TypeOpName(kStringToScalar2),
87    TypeOpName(kStringTrack),
88    TypeOpName(kSubtractInt),
89    TypeOpName(kSubtractScalar),
90    TypeOpName(kToBool),
91    TypeOpName(kUnboxToken),
92    TypeOpName(kUnboxToken2),
93    TypeOpName(kXorInt)
94};
95
96static size_t gOpNamesSize = sizeof(gOpNames) / sizeof(gOpNames[0]);
97
98#define OperandName(op) {SkOperand2::op, #op }
99
100static const struct OperName {
101    SkOperand2::OpType fType;
102    const char* fName;
103} gOperandNames[] = {
104    OperandName(kNoType),
105    OperandName(kS32),
106    OperandName(kScalar),
107    OperandName(kString),
108    OperandName(kArray),
109    OperandName(kObject)
110};
111
112static size_t gOperandNamesSize = sizeof(gOperandNames) / sizeof(gOperandNames[0]);
113
114// check to see that there are no missing or duplicate entries
115void SkScriptEngine2::ValidateDecompileTable() {
116    SkScriptEngine2::TypeOp op = SkScriptEngine2::kNop;
117    size_t index;
118    for (index = 0; index < gOpNamesSize; index++) {
119        SkASSERT(gOpNames[index].fOp == op);
120        op = (SkScriptEngine2::TypeOp) (op + 1);
121    }
122    index = 0;
123    SkOperand2::OpType type = SkOperand2::kNoType;
124    SkASSERT(gOperandNames[index].fType == type);
125    for (; index < gOperandNamesSize - 1; ) {
126        type = (SkOperand2::OpType) (1 << index);
127        SkASSERT(gOperandNames[++index].fType == type);
128    }
129}
130
131void SkScriptEngine2::decompile(const unsigned char* start, size_t length) {
132    SkASSERT(length > 0);
133    const unsigned char* opCode = start;
134    do {
135        SkASSERT((size_t)(opCode - start) < length);
136        SkScriptEngine2::TypeOp op = (SkScriptEngine2::TypeOp) *opCode++;
137        SkASSERT((size_t)op < gOpNamesSize);
138        SkDebugf("%d: %s", opCode - start - 1, gOpNames[op].fName);
139        switch (op) {
140        case SkScriptEngine2::kCallback: {
141            int index;
142            memcpy(&index, opCode, sizeof(index));
143            opCode += sizeof(index);
144            SkDebugf(" index: %d", index);
145            } break;
146        case SkScriptEngine2::kFunctionCall:
147        case SkScriptEngine2::kMemberOp:
148        case SkScriptEngine2::kPropertyOp: {
149            size_t ref;
150            memcpy(&ref, opCode, sizeof(ref));
151            opCode += sizeof(ref);
152            SkDebugf(" ref: %d", ref);
153            } break;
154        case SkScriptEngine2::kIntegerAccumulator:
155        case SkScriptEngine2::kIntegerOperand: {
156            int32_t integer;
157            memcpy(&integer, opCode, sizeof(integer));
158            opCode += sizeof(int32_t);
159            SkDebugf(" integer: %d", integer);
160            } break;
161        case SkScriptEngine2::kScalarAccumulator:
162        case SkScriptEngine2::kScalarOperand: {
163            SkScalar scalar;
164            memcpy(&scalar, opCode, sizeof(scalar));
165            opCode += sizeof(SkScalar);
166#ifdef SK_CAN_USE_FLOAT
167            SkDebugf(" scalar: %g", SkScalarToFloat(scalar));
168#else
169            SkDebugf(" scalar: %x", scalar);
170#endif
171            } break;
172        case SkScriptEngine2::kStringAccumulator:
173        case SkScriptEngine2::kStringOperand: {
174            int size;
175            SkString* strPtr = new SkString();
176            memcpy(&size, opCode, sizeof(size));
177            opCode += sizeof(size);
178            strPtr->set((char*) opCode, size);
179            opCode += size;
180            SkDebugf(" string: %s", strPtr->c_str());
181            delete strPtr;
182            } break;
183        case SkScriptEngine2::kBoxToken: {
184            SkOperand2::OpType type;
185            memcpy(&type, opCode, sizeof(type));
186            opCode += sizeof(type);
187            size_t index = 0;
188            if (type == 0)
189                SkDebugf(" type: %s", gOperandNames[index].fName);
190            else {
191                while (type != 0) {
192                    SkASSERT(index + 1 < gOperandNamesSize);
193                    if (type & (1 << index)) {
194                        type = (SkOperand2::OpType) (type & ~(1 << index));
195                        SkDebugf(" type: %s", gOperandNames[index + 1].fName);
196                    }
197                    index++;
198                }
199            }
200            } break;
201        case SkScriptEngine2::kIfOp:
202        case SkScriptEngine2::kLogicalAndInt:
203        case SkScriptEngine2::kElseOp:
204        case SkScriptEngine2::kLogicalOrInt: {
205            int size;
206            memcpy(&size, opCode, sizeof(size));
207            opCode += sizeof(size);
208            SkDebugf(" offset (address): %d (%d)", size, opCode - start + size);
209            } break;
210        case SkScriptEngine2::kEnd:
211            goto done;
212        case SkScriptEngine2::kNop:
213                SkASSERT(0);
214        default:
215            break;
216    }
217    SkDebugf("\n");
218    } while (true);
219done:
220    SkDebugf("\n");
221}
222
223#endif
224