@awayfl/avm1
Version:
Virtual machine for executing AS1 and AS2 code
162 lines (161 loc) • 6.47 kB
JavaScript
/*
* 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 };