[swfinterp] Add more builtins and improve static variables
This commit is contained in:
parent
1921b24551
commit
fbf94a7815
2 changed files with 49 additions and 8 deletions
18
test/swftests/ConstArrayAccess.as
Normal file
18
test/swftests/ConstArrayAccess.as
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// input: []
|
||||||
|
// output: 4
|
||||||
|
|
||||||
|
package {
|
||||||
|
public class ConstArrayAccess {
|
||||||
|
private static const x:int = 2;
|
||||||
|
private static const ar:Array = ["42", "3411"];
|
||||||
|
|
||||||
|
public static function main():int{
|
||||||
|
var c:ConstArrayAccess = new ConstArrayAccess();
|
||||||
|
return c.f();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function f(): int {
|
||||||
|
return ar[1].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,13 +62,14 @@ class _ScopeDict(dict):
|
||||||
|
|
||||||
|
|
||||||
class _AVMClass(object):
|
class _AVMClass(object):
|
||||||
def __init__(self, name_idx, name):
|
def __init__(self, name_idx, name, static_properties=None):
|
||||||
self.name_idx = name_idx
|
self.name_idx = name_idx
|
||||||
self.name = name
|
self.name = name
|
||||||
self.method_names = {}
|
self.method_names = {}
|
||||||
self.method_idxs = {}
|
self.method_idxs = {}
|
||||||
self.methods = {}
|
self.methods = {}
|
||||||
self.method_pyfunctions = {}
|
self.method_pyfunctions = {}
|
||||||
|
self.static_properties = static_properties if static_properties else {}
|
||||||
|
|
||||||
self.variables = _ScopeDict(self)
|
self.variables = _ScopeDict(self)
|
||||||
self.constants = {}
|
self.constants = {}
|
||||||
|
@ -151,15 +152,20 @@ def _read_byte(reader):
|
||||||
|
|
||||||
StringClass = _AVMClass('(no name idx)', 'String')
|
StringClass = _AVMClass('(no name idx)', 'String')
|
||||||
ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray')
|
ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray')
|
||||||
|
TimerClass = _AVMClass('(no name idx)', 'Timer')
|
||||||
|
TimerEventClass = _AVMClass('(no name idx)', 'TimerEvent', {'TIMER': 'timer'})
|
||||||
_builtin_classes = {
|
_builtin_classes = {
|
||||||
StringClass.name: StringClass,
|
StringClass.name: StringClass,
|
||||||
ByteArrayClass.name: ByteArrayClass,
|
ByteArrayClass.name: ByteArrayClass,
|
||||||
|
TimerClass.name: TimerClass,
|
||||||
|
TimerEventClass.name: TimerEventClass,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class _Undefined(object):
|
class _Undefined(object):
|
||||||
def __boolean__(self):
|
def __bool__(self):
|
||||||
return False
|
return False
|
||||||
|
__nonzero__ = __bool__
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return 0
|
return 0
|
||||||
|
@ -169,7 +175,9 @@ undefined = _Undefined()
|
||||||
|
|
||||||
class SWFInterpreter(object):
|
class SWFInterpreter(object):
|
||||||
def __init__(self, file_contents):
|
def __init__(self, file_contents):
|
||||||
self._patched_functions = {}
|
self._patched_functions = {
|
||||||
|
(TimerClass, 'addEventListener'): lambda params: undefined,
|
||||||
|
}
|
||||||
code_tag = next(tag
|
code_tag = next(tag
|
||||||
for tag_code, tag in _extract_tags(file_contents)
|
for tag_code, tag in _extract_tags(file_contents)
|
||||||
if tag_code == 82)
|
if tag_code == 82)
|
||||||
|
@ -346,9 +354,10 @@ class SWFInterpreter(object):
|
||||||
u30() # iinit
|
u30() # iinit
|
||||||
trait_count = u30()
|
trait_count = u30()
|
||||||
for _c2 in range(trait_count):
|
for _c2 in range(trait_count):
|
||||||
trait_methods, constants = parse_traits_info()
|
trait_methods, trait_constants = parse_traits_info()
|
||||||
avm_class.register_methods(trait_methods)
|
avm_class.register_methods(trait_methods)
|
||||||
assert constants is None
|
if trait_constants:
|
||||||
|
avm_class.constants.update(trait_constants)
|
||||||
|
|
||||||
assert len(classes) == class_count
|
assert len(classes) == class_count
|
||||||
self._classes_by_name = dict((c.name, c) for c in classes)
|
self._classes_by_name = dict((c.name, c) for c in classes)
|
||||||
|
@ -439,7 +448,7 @@ class SWFInterpreter(object):
|
||||||
registers = [avm_class.variables] + list(args) + [None] * m.local_count
|
registers = [avm_class.variables] + list(args) + [None] * m.local_count
|
||||||
stack = []
|
stack = []
|
||||||
scopes = collections.deque([
|
scopes = collections.deque([
|
||||||
self._classes_by_name, avm_class.variables])
|
self._classes_by_name, avm_class.constants, avm_class.variables])
|
||||||
while True:
|
while True:
|
||||||
opcode = _read_byte(coder)
|
opcode = _read_byte(coder)
|
||||||
if opcode == 9: # label
|
if opcode == 9: # label
|
||||||
|
@ -587,6 +596,12 @@ class SWFInterpreter(object):
|
||||||
elif opcode == 72: # returnvalue
|
elif opcode == 72: # returnvalue
|
||||||
res = stack.pop()
|
res = stack.pop()
|
||||||
return res
|
return res
|
||||||
|
elif opcode == 73: # constructsuper
|
||||||
|
# Not yet implemented, just hope it works without it
|
||||||
|
arg_count = u30()
|
||||||
|
args = list(reversed(
|
||||||
|
[stack.pop() for _ in range(arg_count)]))
|
||||||
|
obj = stack.pop()
|
||||||
elif opcode == 74: # constructproperty
|
elif opcode == 74: # constructproperty
|
||||||
index = u30()
|
index = u30()
|
||||||
arg_count = u30()
|
arg_count = u30()
|
||||||
|
@ -667,8 +682,11 @@ class SWFInterpreter(object):
|
||||||
|
|
||||||
if mname in scope:
|
if mname in scope:
|
||||||
res = scope[mname]
|
res = scope[mname]
|
||||||
|
elif mname in _builtin_classes:
|
||||||
|
res = _builtin_classes[mname]
|
||||||
else:
|
else:
|
||||||
res = avm_class.constants[mname]
|
# Assume unitialized
|
||||||
|
res = undefined
|
||||||
stack.append(res)
|
stack.append(res)
|
||||||
elif opcode == 97: # setproperty
|
elif opcode == 97: # setproperty
|
||||||
index = u30()
|
index = u30()
|
||||||
|
@ -694,6 +712,11 @@ class SWFInterpreter(object):
|
||||||
stack.append(len(obj))
|
stack.append(len(obj))
|
||||||
elif isinstance(pname, compat_str): # Member access
|
elif isinstance(pname, compat_str): # Member access
|
||||||
obj = stack.pop()
|
obj = stack.pop()
|
||||||
|
if isinstance(obj, _AVMClass):
|
||||||
|
res = obj.static_properties[pname]
|
||||||
|
stack.append(res)
|
||||||
|
continue
|
||||||
|
|
||||||
assert isinstance(obj, (dict, _ScopeDict)),\
|
assert isinstance(obj, (dict, _ScopeDict)),\
|
||||||
'Accessing member %r on %r' % (pname, obj)
|
'Accessing member %r on %r' % (pname, obj)
|
||||||
res = obj.get(pname, undefined)
|
res = obj.get(pname, undefined)
|
||||||
|
|
Loading…
Reference in a new issue