Author: Stephan <step...@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) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit