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