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