UNPKG

@awayfl/avm1

Version:

Virtual machine for executing AS1 and AS2 code

162 lines (161 loc) 6.47 kB
/* * Copyright 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var ActionsDataAnalyzer = /** @class */ (function () { function ActionsDataAnalyzer() { this.parentResults = null; this.registersLimit = 0; } ActionsDataAnalyzer.prototype.analyze = function (parser) { var actions = []; var labels = [0]; var processedLabels = [true]; var constantPoolFound = false; var singleConstantPoolAt0 = null; // Parsing all actions we can reach. Every action will have next position // and conditional jump location. var queue = [0]; var position; var action; var nextPosition; var item; var jumpPosition; var branching; var nonConditionalBranching; var skipCount; while (queue.length > 0) { position = queue.shift(); if (actions[position]) { continue; } parser.position = position; // reading block of actions until the first jump of end of actions while (!parser.eof && !actions[position]) { action = parser.readNext(); if (action.actionCode === 0) { break; } nextPosition = parser.position; item = { action: action, next: nextPosition, conditionalJumpTo: -1 }; jumpPosition = 0; branching = false; nonConditionalBranching = false; switch (action.actionCode) { case 138 /* ActionCode.ActionWaitForFrame */: case 141 /* ActionCode.ActionWaitForFrame2 */: branching = true; // skip is specified in amount of actions (instead of bytes) skipCount = action.actionCode === 138 /* ActionCode.ActionWaitForFrame */ ? action.args[1] : action.args[0]; parser.skip(skipCount); jumpPosition = parser.position; parser.position = nextPosition; break; case 153 /* ActionCode.ActionJump */: nonConditionalBranching = true; branching = true; jumpPosition = nextPosition + action.args[0]; break; case 157 /* ActionCode.ActionIf */: branching = true; jumpPosition = nextPosition + action.args[0]; break; case 42 /* ActionCode.ActionThrow */: case 62 /* ActionCode.ActionReturn */: case 0 /* ActionCode.None */: nonConditionalBranching = true; branching = true; jumpPosition = parser.length; break; case 136 /* ActionCode.ActionConstantPool */: if (constantPoolFound) { singleConstantPoolAt0 = null; // reset if more than one found break; } constantPoolFound = true; if (position === 0) { // For now only counting at position 0 of the block of actions singleConstantPoolAt0 = action.args[0]; } break; } if (branching) { if (nonConditionalBranching) { item.next = jumpPosition; } else { item.conditionalJumpTo = jumpPosition; } if (!processedLabels[jumpPosition]) { labels.push(jumpPosition); queue.push(jumpPosition); processedLabels[jumpPosition] = true; } } actions[position] = item; if (nonConditionalBranching) { break; } position = nextPosition; } } // Creating blocks for every unique label var blocks = []; var items; var lastPosition; labels.forEach(function (position) { if (!actions[position]) { return; } items = []; lastPosition = position; var item; // continue grabbing items until other label or next code exist do { item = actions[lastPosition]; items.push(item); lastPosition = item.next; } while (!processedLabels[lastPosition] && actions[lastPosition]); blocks.push({ label: position, items: items, jump: lastPosition }); }); // Determines if action blocks (or defined function) is using the single // constants pool defined at the beginning of the action block. var singleConstantPool = null; if (constantPoolFound) { singleConstantPool = singleConstantPoolAt0; } else if (this.parentResults) { // Trying to use parent's constant pool if available. singleConstantPool = this.parentResults.singleConstantPool; } return { actions: actions, blocks: blocks, dataId: parser.dataId, singleConstantPool: singleConstantPool, registersLimit: this.registersLimit }; }; return ActionsDataAnalyzer; }()); export { ActionsDataAnalyzer };