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 
~SkScriptRuntime()55 SkScriptRuntime::~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 
executeTokens(unsigned char * opCode)62 bool 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 = 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);
319 done:
320     fRunStack.push(operand[0]);
321     return true;
322 }
323 
getResult(SkOperand2 * result)324 bool SkScriptRuntime::getResult(SkOperand2* result) {
325     if (fRunStack.count() == 0)
326         return false;
327     fRunStack.pop(result);
328     return true;
329 }
330 
track(SkOpArray * array)331 void SkScriptRuntime::track(SkOpArray* array) {
332     SkASSERT(fTrackArray.find(array) < 0);
333     *fTrackArray.append() = array;
334 }
335 
track(SkString * string)336 void SkScriptRuntime::track(SkString* string) {
337     SkASSERT(fTrackString.find(string) < 0);
338     *fTrackString.append() = string;
339 }
340 
untrack(SkOpArray * array)341 void SkScriptRuntime::untrack(SkOpArray* array) {
342     int index = fTrackArray.find(array);
343     SkASSERT(index >= 0);
344     fTrackArray.begin()[index] = NULL;
345 }
346 
untrack(SkString * string)347 void SkScriptRuntime::untrack(SkString* string) {
348     int index = fTrackString.find(string);
349     SkASSERT(index >= 0);
350     fTrackString.begin()[index] = NULL;
351 }
352