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