1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkScriptRuntime.h"
9#include "SkScript2.h"
10#include "SkMath.h"
11#include "SkParse.h"
12#include "SkScriptCallBack.h"
13#include "SkString.h"
14#include "SkOpArray.h"
15
16// script tokenizer
17
18// turn text into token string
19// turn number literals into inline UTF8-style values
20// process operators to turn standard notation into stack notation
21
22// defer processing until the tokens can all be resolved
23// then, turn token strings into indices into the appropriate tables / dictionaries
24
25// consider: const evaluation?
26
27// replace script string with script tokens preceeded by special value
28
29// need second version of script plugins that return private index of found value?
30    // then would need in script index of plugin, private index
31
32// encode brace stack push/pop as opcodes
33
34// should token script enocde type where possible?
35
36// current flow:
37    // strip whitespace
38    // if in array brace [ recurse, continue
39    // if token, handle function, or array, or property (continue)
40    // parse number, continue
41    // parse token, continue
42    // parse string literal, continue
43    // if dot operator, handle dot, continue
44    // if [ , handle array literal or accessor, continue
45    // if ), pop (if function, break)
46    // if ], pop ; if ',' break
47    // handle logical ops
48    // or, handle arithmetic ops
49    // loop
50
51// !!! things to do
52    // add separate processing loop to advance while suppressed
53    // or, include jump offset to skip suppressed code?
54
55SkScriptRuntime::~SkScriptRuntime() {
56    for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
57        delete *stringPtr;
58    for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
59        delete *arrayPtr;
60}
61
62bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
63    SkOperand2 operand[2];    // 1=accumulator and 2=operand
64    SkScriptEngine2::TypeOp op;
65    size_t ref;
66    int index, size;
67    int registerLoad;
68    SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
69    do {
70    switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
71        case SkScriptEngine2::kArrayToken:    // create an array
72            operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
73            break;
74        case SkScriptEngine2::kArrayIndex:    // array accessor
75            index = operand[1].fS32;
76            if (index >= operand[0].fArray->count()) {
77                fError = kArrayIndexOutOfBounds;
78                return false;
79            }
80            operand[0] = operand[0].fArray->begin()[index];
81            break;
82        case SkScriptEngine2::kArrayParam:    // array initializer, or function param
83            *operand[0].fArray->append() = operand[1];
84            break;
85        case SkScriptEngine2::kCallback:
86            memcpy(&index, opCode, sizeof(index));
87            opCode += sizeof(index);
88            callBack = fCallBackArray[index];
89            break;
90        case SkScriptEngine2::kFunctionCall: {
91            memcpy(&ref, opCode, sizeof(ref));
92            opCode += sizeof(ref);
93            SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
94            if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
95                    &operand[0] /* result */) == false) {
96                fError = kFunctionCallFailed;
97                return false;
98            }
99            } break;
100        case SkScriptEngine2::kMemberOp: {
101            memcpy(&ref, opCode, sizeof(ref));
102            opCode += sizeof(ref);
103            SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
104            if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
105                fError = kMemberOpFailed;
106                return false;
107            }
108            } break;
109        case SkScriptEngine2::kPropertyOp: {
110            memcpy(&ref, opCode, sizeof(ref));
111            opCode += sizeof(ref);
112            SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
113            if (callBackProperty->getResult(ref, &operand[0])== false) {
114                fError = kPropertyOpFailed;
115                return false;
116            }
117            } break;
118        case SkScriptEngine2::kAccumulatorPop:
119            fRunStack.pop(&operand[0]);
120            break;
121        case SkScriptEngine2::kAccumulatorPush:
122            *fRunStack.push() = operand[0];
123            break;
124        case SkScriptEngine2::kIntegerAccumulator:
125        case SkScriptEngine2::kIntegerOperand:
126            registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
127            memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t));
128            opCode += sizeof(int32_t);
129            break;
130        case SkScriptEngine2::kScalarAccumulator:
131        case SkScriptEngine2::kScalarOperand:
132            registerLoad = op - SkScriptEngine2::kScalarAccumulator;
133            memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
134            opCode += sizeof(SkScalar);
135            break;
136        case SkScriptEngine2::kStringAccumulator:
137        case SkScriptEngine2::kStringOperand: {
138            SkString* strPtr = new SkString();
139            track(strPtr);
140            registerLoad = op - SkScriptEngine2::kStringAccumulator;
141            memcpy(&size, opCode, sizeof(size));
142            opCode += sizeof(size);
143            strPtr->set((char*) opCode, size);
144            opCode += size;
145            operand[registerLoad].fString = strPtr;
146            } break;
147        case SkScriptEngine2::kStringTrack: // call after kObjectToValue
148            track(operand[0].fString);
149            break;
150        case SkScriptEngine2::kBoxToken: {
151            SkOperand2::OpType type;
152            memcpy(&type, opCode, sizeof(type));
153            opCode += sizeof(type);
154            SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
155            if (callBackBox->convert(type, &operand[0]) == false)
156                return false;
157            } break;
158        case SkScriptEngine2::kUnboxToken:
159        case SkScriptEngine2::kUnboxToken2: {
160            SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
161            if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
162                return false;
163            } break;
164        case SkScriptEngine2::kIfOp:
165        case SkScriptEngine2::kLogicalAndInt:
166            memcpy(&size, opCode, sizeof(size));
167            opCode += sizeof(size);
168            if (operand[0].fS32 == 0)
169                opCode += size; // skip to else (or end of if predicate)
170            break;
171        case SkScriptEngine2::kElseOp:
172            memcpy(&size, opCode, sizeof(size));
173            opCode += sizeof(size);
174            opCode += size; // if true: after predicate, always skip to end of else
175            break;
176        case SkScriptEngine2::kLogicalOrInt:
177            memcpy(&size, opCode, sizeof(size));
178            opCode += sizeof(size);
179            if (operand[0].fS32 != 0)
180                opCode += size; // skip to kToBool opcode after || predicate
181            break;
182        // arithmetic conversion ops
183        case SkScriptEngine2::kFlipOpsOp:
184            SkTSwap(operand[0], operand[1]);
185            break;
186        case SkScriptEngine2::kIntToString:
187        case SkScriptEngine2::kIntToString2:
188        case SkScriptEngine2::kScalarToString:
189        case SkScriptEngine2::kScalarToString2:{
190            SkString* strPtr = new SkString();
191            track(strPtr);
192            if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
193                strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
194            else
195                strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
196            operand[0].fString = strPtr;
197            } break;
198        case SkScriptEngine2::kIntToScalar:
199        case SkScriptEngine2::kIntToScalar2:
200            operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
201            break;
202        case SkScriptEngine2::kStringToInt:
203            if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == NULL)
204                return false;
205            break;
206        case SkScriptEngine2::kStringToScalar:
207        case SkScriptEngine2::kStringToScalar2:
208            if (SkParse::FindScalar(operand[0].fString->c_str(),
209                    &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == NULL)
210                return false;
211            break;
212        case SkScriptEngine2::kScalarToInt:
213            operand[0].fS32 = SkScalarFloorToInt(operand[0].fScalar);
214            break;
215        // arithmetic ops
216        case SkScriptEngine2::kAddInt:
217            operand[0].fS32 += operand[1].fS32;
218            break;
219        case SkScriptEngine2::kAddScalar:
220            operand[0].fScalar += operand[1].fScalar;
221            break;
222        case SkScriptEngine2::kAddString:
223//            if (fTrackString.find(operand[1].fString) < 0) {
224//                operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
225//                track(operand[1].fString);
226//            }
227            operand[0].fString->append(*operand[1].fString);
228            break;
229        case SkScriptEngine2::kBitAndInt:
230            operand[0].fS32 &= operand[1].fS32;
231            break;
232        case SkScriptEngine2::kBitNotInt:
233            operand[0].fS32 = ~operand[0].fS32;
234            break;
235        case SkScriptEngine2::kBitOrInt:
236            operand[0].fS32 |= operand[1].fS32;
237            break;
238        case SkScriptEngine2::kDivideInt:
239            SkASSERT(operand[1].fS32 != 0);
240            if (operand[1].fS32 == 0)
241                operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 :
242                    operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
243            else
244            if (operand[1].fS32 != 0) // throw error on divide by zero?
245                operand[0].fS32 /= operand[1].fS32;
246            break;
247        case SkScriptEngine2::kDivideScalar:
248            if (operand[1].fScalar == 0)
249                operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN :
250                    operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
251            else
252                operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar);
253            break;
254        case SkScriptEngine2::kEqualInt:
255            operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
256            break;
257        case SkScriptEngine2::kEqualScalar:
258            operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
259            break;
260        case SkScriptEngine2::kEqualString:
261            operand[0].fS32 = *operand[0].fString == *operand[1].fString;
262            break;
263        case SkScriptEngine2::kGreaterEqualInt:
264            operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
265            break;
266        case SkScriptEngine2::kGreaterEqualScalar:
267            operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
268            break;
269        case SkScriptEngine2::kGreaterEqualString:
270            operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
271            break;
272        case SkScriptEngine2::kToBool:
273            operand[0].fS32 = !! operand[0].fS32;
274            break;
275        case SkScriptEngine2::kLogicalNotInt:
276            operand[0].fS32 = ! operand[0].fS32;
277            break;
278        case SkScriptEngine2::kMinusInt:
279            operand[0].fS32 = -operand[0].fS32;
280            break;
281        case SkScriptEngine2::kMinusScalar:
282            operand[0].fScalar = -operand[0].fScalar;
283            break;
284        case SkScriptEngine2::kModuloInt:
285            operand[0].fS32 %= operand[1].fS32;
286            break;
287        case SkScriptEngine2::kModuloScalar:
288            operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
289            break;
290        case SkScriptEngine2::kMultiplyInt:
291            operand[0].fS32 *= operand[1].fS32;
292            break;
293        case SkScriptEngine2::kMultiplyScalar:
294            operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
295            break;
296        case SkScriptEngine2::kShiftLeftInt:
297            operand[0].fS32 <<= operand[1].fS32;
298            break;
299        case SkScriptEngine2::kShiftRightInt:
300            operand[0].fS32 >>= operand[1].fS32;
301            break;
302        case SkScriptEngine2::kSubtractInt:
303            operand[0].fS32 -= operand[1].fS32;
304            break;
305        case SkScriptEngine2::kSubtractScalar:
306            operand[0].fScalar -= operand[1].fScalar;
307            break;
308        case SkScriptEngine2::kXorInt:
309            operand[0].fS32 ^= operand[1].fS32;
310            break;
311        case SkScriptEngine2::kEnd:
312            goto done;
313        case SkScriptEngine2::kNop:
314                SkASSERT(0);
315    default:
316        break;
317    }
318    } while (true);
319done:
320    fRunStack.push(operand[0]);
321    return true;
322}
323
324bool SkScriptRuntime::getResult(SkOperand2* result) {
325    if (fRunStack.count() == 0)
326        return false;
327    fRunStack.pop(result);
328    return true;
329}
330
331void SkScriptRuntime::track(SkOpArray* array) {
332    SkASSERT(fTrackArray.find(array) < 0);
333    *fTrackArray.append() = array;
334}
335
336void SkScriptRuntime::track(SkString* string) {
337    SkASSERT(fTrackString.find(string) < 0);
338    *fTrackString.append() = string;
339}
340
341void SkScriptRuntime::untrack(SkOpArray* array) {
342    int index = fTrackArray.find(array);
343    SkASSERT(index >= 0);
344    fTrackArray.begin()[index] = NULL;
345}
346
347void SkScriptRuntime::untrack(SkString* string) {
348    int index = fTrackString.find(string);
349    SkASSERT(index >= 0);
350    fTrackString.begin()[index] = NULL;
351}
352