[pypy-commit] lang-js default: re-enabled and fixed virtualizables
stepahn
noreply at buildbot.pypy.org
Sun Feb 3 17:38:36 CET 2013
Author: Stephan <stephan at stzal.com>
Branch:
Changeset: r347:4d28120584cd
Date: 2013-02-01 13:20 +0100
http://bitbucket.org/pypy/lang-js/changeset/4d28120584cd/
Log: re-enabled and fixed virtualizables
diff --git a/js/completion.py b/js/completion.py
--- a/js/completion.py
+++ b/js/completion.py
@@ -2,6 +2,8 @@
# 8.9
class Completion(object):
+ _immutable_fields_ = ['value', 'target']
+
def __init__(self, value=None, target=None):
self.value = value
self.target = target
diff --git a/js/environment_record.py b/js/environment_record.py
--- a/js/environment_record.py
+++ b/js/environment_record.py
@@ -83,7 +83,11 @@
if self._binding_map_.not_found(idx):
return
- del(self._binding_slots_[idx])
+ assert idx >= 0
+ i = (idx + 1)
+ assert i >= 0
+
+ self._binding_slots_ = self._binding_slots_[:idx] + self._binding_slots_[i:] #len(self._binding_slots_)]
self._binding_map_ = self._binding_map_.delete(name)
# 10.2.1.1.2
@@ -126,7 +130,7 @@
return False
if self._is_deletable_binding(identifier) is False:
return False
- self._deletable_bindings_map__ = self._deletable_bindings_map_.delete(identifier)
+ self._deletable_bindings_map_ = self._deletable_bindings_map_.delete(identifier)
self._mutable_bindings_map_ = self._mutable_bindings_map_.delete(identifier)
self._del_binding(identifier)
return False
diff --git a/js/execution_context.py b/js/execution_context.py
--- a/js/execution_context.py
+++ b/js/execution_context.py
@@ -1,12 +1,15 @@
from js.utils import StackMixin
from js.object_space import newundefined
+from pypy.rlib import jit
class ExecutionContext(StackMixin):
- _immutable_fields_ = ['_stack_', '_stack_resize_', '_this_binding_', '_lexical_environment_', '_variable_environment_']
- _refs_resizable_ = True
+ _immutable_fields_ = ['_stack_', '_this_binding_', '_lexical_environment_', '_variable_environment_', '_refs_', '_code_', '_formal_parameters_', '_argument_values_', '_w_func_'] # TODO why are _formal_parameters_, _w_func_ etc. required here?
+ _virtualizable2_ = ['_stack_[*]', '_stack_pointer_', '_refs_[*]']
+ _settled_ = True
def __init__(self, stack_size=1, refs_size=1):
+ self = jit.hint(self, access_directly=True, fresh_virtualizable=True)
self._lexical_environment_ = None
self._variable_environment_ = None
self._this_binding_ = None
@@ -22,6 +25,7 @@
def stack_top(self):
return self._stack_top()
+ @jit.unroll_safe
def stack_pop_n(self, n):
if n < 1:
return []
@@ -51,12 +55,13 @@
self._lexical_environment_ = lex_env
# 10.5
+ @jit.unroll_safe
def declaration_binding_initialization(self):
from js.object_space import newundefined
env = self._variable_environment_.environment_record
strict = self._strict_
- code = self._code_
+ code = jit.promote(self._code_)
if code.is_eval_code():
configurable_bindings = True
@@ -65,7 +70,7 @@
# 4.
if code.is_function_code():
- names = self._formal_parameters_
+ names = code.params() #_formal_parameters_
n = 0
args = self._argument_values_
@@ -99,7 +104,7 @@
# TODO get calling W_Function
func = self._w_func_
arguments = self._argument_values_
- names = self._formal_parameters_
+ names = code.params() #_formal_parameters_
args_obj = W_Arguments(func, names, arguments, env, strict)
if strict is True:
@@ -118,41 +123,60 @@
env.set_mutable_binding(dn, newundefined(), False)
def _get_refs(self, index):
- assert index <= len(self._refs_)
+ assert index < len(self._refs_)
+ assert index >= 0
return self._refs_[index]
def _set_refs(self, index, value):
- assert index <= len(self._refs_)
+ assert index < len(self._refs_)
+ assert index >= 0
self._refs_[index] = value
def get_ref(self, symbol, index=-1):
## TODO pre-bind symbols, work with idndex, does not work, see test_foo19
- if index == -1:
+ if index < 0:
lex_env = self.lexical_environment()
ref = lex_env.get_identifier_reference(symbol)
return ref
- if self._refs_resizable_ is True and index >= len(self._refs_):
- self._refs_ += ([None] * (1 + index - len(self._refs_)))
+ ref = self._get_refs(index)
- if self._get_refs(index) is None:
+ if ref is None:
lex_env = self.lexical_environment()
ref = lex_env.get_identifier_reference(symbol)
if ref.is_unresolvable_reference() is True:
return ref
self._set_refs(index, ref)
- return self._get_refs(index)
+ return ref
def forget_ref(self, symbol, index):
self._set_refs(index, None)
-class GlobalExecutionContext(ExecutionContext):
+class _DynamicExecutionContext(ExecutionContext):
+ def __init__(self, stack_size):
+ ExecutionContext.__init__(self, stack_size)
+ self._dyn_refs_ = [None]
+
+ def _get_refs(self, index):
+ self._resize_refs(index)
+ return self._dyn_refs_[index]
+
+ def _set_refs(self, index, value):
+ self._resize_refs(index)
+ self._dyn_refs_[index] = value
+
+ def _resize_refs(self, index):
+ if index >= len(self._dyn_refs_):
+ self._dyn_refs_ += ([None] * (1 + index - len(self._dyn_refs_)))
+
+
+class GlobalExecutionContext(_DynamicExecutionContext):
def __init__(self, code, global_object, strict=False):
stack_size = code.estimated_stack_size()
- ExecutionContext.__init__(self, stack_size)
+ _DynamicExecutionContext.__init__(self, stack_size)
self._code_ = code
self._strict_ = strict
@@ -166,11 +190,11 @@
self.declaration_binding_initialization()
-class EvalExecutionContext(ExecutionContext):
+class EvalExecutionContext(_DynamicExecutionContext):
def __init__(self, code, calling_context=None):
stack_size = code.estimated_stack_size()
- ExecutionContext.__init__(self, stack_size)
+ _DynamicExecutionContext.__init__(self, stack_size)
self._code_ = code
self._strict_ = code.strict
@@ -191,7 +215,6 @@
class FunctionExecutionContext(ExecutionContext):
_immutable_fields_ = ['_scope_', '_calling_context_']
- _refs_resizable_ = False
def __init__(self, code, formal_parameters=[], argv=[], this=newundefined(), strict=False, scope=None, w_func=None):
from js.jsobj import W_BasicObject
@@ -203,7 +226,6 @@
ExecutionContext.__init__(self, stack_size, env_size)
self._code_ = code
- self._formal_parameters_ = formal_parameters
self._argument_values_ = argv
self._strict_ = strict
self._scope_ = scope
@@ -234,9 +256,9 @@
return self._argument_values_
-class SubExecutionContext(ExecutionContext):
+class SubExecutionContext(_DynamicExecutionContext):
def __init__(self, parent):
- ExecutionContext.__init__(self)
+ _DynamicExecutionContext.__init__(self, 0)
self._parent_context_ = parent
def stack_append(self, value):
@@ -261,6 +283,7 @@
self._code_ = code
self._strict_ = code.strict
self._expr_obj_ = expr_obj
+ self._dynamic_refs = []
from js.lexical_environment import ObjectEnvironment
parent_environment = parent_context.lexical_environment()
@@ -273,16 +296,16 @@
self.declaration_binding_initialization()
-class CatchExecutionContext(ExecutionContext):
+class CatchExecutionContext(_DynamicExecutionContext):
def __init__(self, code, catchparam, exception_value, parent_context):
self._code_ = code
self._strict_ = code.strict
self._parent_context_ = parent_context
stack_size = code.estimated_stack_size()
- env_size = code.env_size() + 1 # neet do add one for the arguments object
+ #env_size = code.env_size() + 1 # neet do add one for the arguments object
- ExecutionContext.__init__(self, stack_size, env_size)
+ _DynamicExecutionContext.__init__(self, stack_size)
parent_env = parent_context.lexical_environment()
diff --git a/js/functions.py b/js/functions.py
--- a/js/functions.py
+++ b/js/functions.py
@@ -2,6 +2,7 @@
class JsBaseFunction(object):
+ _settled_ = True
eval_code = False
function_code = False
configurable_bindings = False
@@ -63,6 +64,7 @@
args = ctx.argv()
this = ctx.this_binding()
+ assert isinstance(self, JsNativeFunction)
res = self._function_(this, args)
w_res = _w(res)
compl = ReturnCompletion(value=w_res)
@@ -98,6 +100,7 @@
from js.jscode import JsCode
assert isinstance(js_code, JsCode)
self._js_code_ = js_code
+ self._js_code_.compile()
self._stack_size_ = js_code.estimated_stack_size()
self._symbol_size_ = js_code.symbol_size()
@@ -122,8 +125,10 @@
return code.variables()
def functions(self):
+ # XXX tuning
code = self.get_js_code()
- return code.functions()
+ functions = code.functions()
+ return functions
def params(self):
code = self.get_js_code()
diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -16,8 +16,7 @@
else:
return '%d: %s' % (pc, 'end of opcodes')
-#jitdriver = JitDriver(greens=['pc', 'self'], reds=['ctx'], get_printable_location = get_printable_location, virtualizables=['ctx'])
-jitdriver = JitDriver(greens=['pc', 'debug', 'self'], reds=['result', 'ctx'], get_printable_location=get_printable_location)
+jitdriver = JitDriver(greens=['pc', 'debug', 'self'], reds=['result', 'ctx'], get_printable_location=get_printable_location, virtualizables=['ctx'])
def ast_to_bytecode(ast, symbol_map):
@@ -32,7 +31,7 @@
class JsCode(object):
- _immutable_fields_ = ['_oppcodes_', '_symbols_']
+ _immutable_fields_ = ['compiled_opcodes[*]', '_symbols', 'parameters[*]']
""" That object stands for code of a single javascript function
"""
@@ -46,6 +45,7 @@
self.updatelooplabel = []
self._estimated_stack_size = -1
self._symbols = symbol_map
+ self.parameters = symbol_map.parameters[:]
def variables(self):
return self._symbols.variables
@@ -62,8 +62,9 @@
def symbol_for_index(self, index):
return self._symbols.get_symbol(index)
+ @jit.unroll_safe
def params(self):
- return self._symbols.parameters
+ return [p for p in self.parameters]
#@jit.elidable
def estimated_stack_size(self):
@@ -71,7 +72,7 @@
if self._estimated_stack_size == -1:
max_size = 0
moving_size = 0
- for opcode in self.opcodes:
+ for opcode in self.compiled_opcodes:
moving_size += opcode.stack_change()
max_size = max(moving_size, max_size)
assert max_size >= 0
@@ -167,7 +168,9 @@
if self.has_labels:
self.remove_labels()
+ def compile(self):
self.unlabel()
+ self.compiled_opcodes = [o for o in self.opcodes]
def remove_labels(self):
""" Basic optimization to remove all labels and change
@@ -192,10 +195,11 @@
@jit.elidable
def _get_opcode(self, pc):
assert pc >= 0
- return self.opcodes[pc]
+ return self.compiled_opcodes[pc]
+ @jit.elidable
def _opcode_count(self):
- return len(self.opcodes)
+ return len(self.compiled_opcodes)
def run(self, ctx):
from js.object_space import object_space
@@ -203,8 +207,6 @@
from js.completion import NormalCompletion, is_completion, is_return_completion, is_empty_completion
from js.opcodes import BaseJump
- self.unlabel()
-
if self._opcode_count() == 0:
return NormalCompletion()
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -179,7 +179,7 @@
_type_ = 'object'
_class_ = 'Object'
_extensible_ = True
- _immutable_fields_ = ['_type_', '_class_', '_extensible_']
+ _immutable_fields_ = ['_type_', '_class_'] # TODO why need _primitive_value_ here???
def __init__(self):
from js.object_space import newnull
@@ -532,6 +532,8 @@
class W__PrimitiveObject(W_BasicObject):
+ _immutable_fields_ = ['_primitive_value_']
+
def __init__(self, primitive_value):
W_BasicObject.__init__(self)
self.set_primitive_value(primitive_value)
@@ -832,7 +834,7 @@
class W__Function(W_BasicFunction):
- _immutable_fields_ = ['_type_', '_class_', '_extensible_', '_scope_', '_params_', '_strict_', '_function_']
+ _immutable_fields_ = ['_type_', '_class_', '_extensible_', '_scope_', '_params_[*]', '_strict_', '_function_']
def __init__(self, function_body, formal_parameter_list=[], scope=None, strict=False):
W_BasicFunction.__init__(self)
@@ -874,12 +876,11 @@
from js.completion import Completion
code = self.code()
- argn = self.formal_parameters()
+ jit.promote(code)
strict = self._strict_
scope = self.scope()
ctx = FunctionExecutionContext(code,
- formal_parameters=argn,
argv=args,
this=this,
strict=strict,
@@ -910,6 +911,7 @@
class W_Arguments(W__Object):
_class_ = 'Arguments'
+ @jit.unroll_safe
def __init__(self, func, names, args, env, strict=False):
from js.object_space import _w
W__Object.__init__(self)
@@ -919,22 +921,22 @@
from js.object_space import object_space
_map = object_space.new_obj()
- mapped_names = []
+ mapped_names = _new_map()
indx = _len - 1
while indx >= 0:
val = args[indx]
put_property(self, unicode(str(indx)), val, writable=True, enumerable=True, configurable=True)
if indx < len(names):
name = names[indx]
- if strict is False and name not in mapped_names:
- mapped_names.append(name)
+ if strict is False and not mapped_names.contains(name):
+ mapped_names = mapped_names.add(name)
g = make_arg_getter(name, env)
p = make_arg_setter(name, env)
desc = PropertyDescriptor(setter=p, getter=g, configurable=True)
_map.define_own_property(unicode(str(indx)), desc, False)
indx = indx - 1
- if len(mapped_names) > 0:
+ if not mapped_names.empty():
self._paramenter_map_ = _map
if strict is False:
diff --git a/js/lexical_environment.py b/js/lexical_environment.py
--- a/js/lexical_environment.py
+++ b/js/lexical_environment.py
@@ -11,7 +11,6 @@
exists = envRec.has_binding(identifier)
if exists:
ref = Reference(base_env=envRec, referenced=identifier, strict=strict)
- jit.promote(ref)
return ref
else:
outer = lex.outer_environment
diff --git a/js/object_map.py b/js/object_map.py
--- a/js/object_map.py
+++ b/js/object_map.py
@@ -3,7 +3,7 @@
class Map(object):
NOT_FOUND = -1
- _immutable_fields_ = ['index', 'back', 'name', 'forward_pointers']
+ _immutable_fields_ = ['index', 'back', 'name']
def __init__(self):
self.index = self.NOT_FOUND
@@ -40,6 +40,12 @@
def _key(self):
return (self.name)
+ def empty(self):
+ return True
+
+ def len(self):
+ return self.index
+
@jit.elidable
def add(self, name):
assert self.lookup(name) == self.NOT_FOUND
@@ -84,6 +90,9 @@
n = self.back.delete(name)
return n.add(self.name)
+ def empty(self):
+ return False
+
ROOT_MAP = MapRoot()
diff --git a/js/opcodes.py b/js/opcodes.py
--- a/js/opcodes.py
+++ b/js/opcodes.py
@@ -5,11 +5,12 @@
from pypy.rlib.rarithmetic import intmask
from js.jsobj import put_property
+from pypy.rlib import jit
class Opcode(object):
_settled_ = True
- _immutable_fields_ = ['_stack_change']
+ _immutable_fields_ = ['_stack_change', 'funcobj']
_stack_change = 1
def __init__(self):
@@ -171,6 +172,7 @@
def __init__(self, counter):
self.counter = counter
+ @jit.unroll_safe
def eval(self, ctx):
from js.object_space import object_space
array = object_space.new_array()
@@ -206,7 +208,7 @@
class LOAD_FUNCTION(Opcode):
- #_immutable_fields_ = ['funcobj']
+ _immutable_fields_ = ['funcobj']
def __init__(self, funcobj):
self.funcobj = funcobj
@@ -233,11 +235,13 @@
def __init__(self, counter):
self.counter = counter
+ @jit.unroll_safe
def eval(self, ctx):
from js.object_space import object_space
w_obj = object_space.new_obj()
for _ in range(self.counter):
- name = ctx.stack_pop().to_string()
+ top = ctx.stack_pop()
+ name = top.to_string()
w_elem = ctx.stack_pop()
put_property(w_obj, name, w_elem, writable=True, configurable=True, enumerable=True)
ctx.stack_append(w_obj)
@@ -307,7 +311,7 @@
def eval(self, ctx):
from js.object_space import newstring
- ref = ctx.get_ref(self.name)
+ ref = ctx.get_ref(self.name, self.index)
if ref.is_unresolvable_reference():
var_type = u'undefined'
else:
@@ -800,14 +804,9 @@
class LOAD_ITERATOR(Opcode):
_stack_change = 0
- def eval(self, ctx):
- exper_value = ctx.stack_pop()
- obj = exper_value.ToObject()
+ # separate function because jit should trace eval but not iterator creation.
+ def _make_iterator(self, obj):
props = []
-
- from js.jsobj import W_BasicObject
- assert isinstance(obj, W_BasicObject)
-
properties = obj.named_properties()
TimSort(properties).sort()
@@ -817,8 +816,19 @@
props.append(_w(key))
props.reverse()
+
from js.jsobj import W_Iterator
iterator = W_Iterator(props)
+ return iterator
+
+ def eval(self, ctx):
+ exper_value = ctx.stack_pop()
+ obj = exper_value.ToObject()
+
+ from js.jsobj import W_BasicObject
+ assert isinstance(obj, W_BasicObject)
+
+ iterator = self._make_iterator(obj)
ctx.stack_append(iterator)
diff --git a/test/test_environment_record.py b/test/test_environment_record.py
--- a/test/test_environment_record.py
+++ b/test/test_environment_record.py
@@ -4,12 +4,12 @@
class TestDeclarativeEnvironmentRecord(object):
def test_create_mutable_binding(self):
- env_rec = DeclarativeEnvironmentRecord()
+ env_rec = DeclarativeEnvironmentRecord(size=1)
env_rec.create_mutuable_binding(u'foo', True)
assert env_rec.has_binding(u'foo') is True
def test_set_and_get_mutable_binding(self):
- env_rec = DeclarativeEnvironmentRecord()
+ env_rec = DeclarativeEnvironmentRecord(size=1)
env_rec.create_mutuable_binding(u'foo', True)
env_rec.set_mutable_binding(u'foo', 42, False)
assert env_rec.get_binding_value(u'foo') == 42
diff --git a/test/test_jsfunction.py b/test/test_jsfunction.py
--- a/test/test_jsfunction.py
+++ b/test/test_jsfunction.py
@@ -50,11 +50,12 @@
var_idx = symbol_map.add_variable(u'a')
code = JsCode(symbol_map)
+ code.parameters = [u'a']
code.emit('LOAD_VARIABLE', var_idx, u'a')
code.emit('RETURN')
f = JsFunction(u'foo', code)
- ctx = FunctionExecutionContext(f, argv=[_w(42)], formal_parameters=[u'a'])
+ ctx = FunctionExecutionContext(f, argv=[_w(42)])
res = f.run(ctx)
assert res.value == _w(42)
More information about the pypy-commit
mailing list