Author: Stephan <[email protected]>
Branch: 
Changeset: r116:9687d1b2f249
Date: 2011-09-04 14:05 +0200
http://bitbucket.org/pypy/lang-js/changeset/9687d1b2f249/

Log:    replaced jsobj.ExecutionContext with new
        jsexecution_context.ExecutionContext

diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -4,7 +4,7 @@
 random = rrandom.Random(int(time.time()))
 from js.jsparser import parse, ParseError
 from js.astbuilder import ASTBuilder
-from js.jsobj import global_context, W_Object,\
+from js.jsobj import W_Object,\
      w_Undefined, W_NewBuiltin, W_IntNumber, w_Null, create_object, W_Boolean,\
      W_FloatNumber, W_String, W_Builtin, W_Array, w_Null, newbool,\
      isnull_or_undefined, W_PrimitiveObject, W_ListObject, W_BaseNumber,\
@@ -717,9 +717,9 @@
     """Creates a js interpreter"""
     def __init__(self):
         allon = DE | DD | RO
-        w_Global = W_Object(Class="global")
-
-        ctx = global_context(w_Global)
+        from js.jsexecution_context import GlobalContext
+        ctx = GlobalContext()
+        w_Global = ctx.to_context_object()
 
         w_ObjPrototype = W_Object(Prototype=None, Class='Object')
 
diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -14,7 +14,7 @@
     except IndexError:
         return "???"
 
-jitdriver = JitDriver(greens=['pc', 'self'], reds=['to_pop', 'ctx'], 
get_printable_location = get_printable_location, virtualizables=['ctx'])
+jitdriver = JitDriver(greens=['pc', 'self'], reds=['ctx'], 
get_printable_location = get_printable_location, virtualizables=['ctx'])
 
 class AlreadyRun(Exception):
     pass
@@ -164,10 +164,11 @@
 
         try:
             r = self.run_bytecode(ctx, check_stack)
-            _restore_stack(ctx, state)
             return r
         except ReturnException, e:
             return e.value
+        finally:
+            _restore_stack(ctx, state)
 
     def _get_opcode(self, pc):
         assert pc >= 0
@@ -175,44 +176,40 @@
 
     def run_bytecode(self, ctx, check_stack=True):
         pc = 0
-        to_pop = 0
-        try:
-            while True:
-                jitdriver.jit_merge_point(pc=pc, self=self, ctx=ctx, 
to_pop=to_pop)
-                if pc >= len(self.opcodes):
-                    break
+        while True:
+            jitdriver.jit_merge_point(pc=pc, self=self, ctx=ctx)
+            if pc >= len(self.opcodes):
+                break
 
-                opcode = self._get_opcode(pc)
-                #if we_are_translated():
-                #    #this is an optimization strategy for translated code
-                #    #on top of cpython it destroys the performance
-                #    #besides, this code might be completely wrong
-                #    for name, op in opcode_unrolling:
-                #        opcode = hint(opcode, deepfreeze=True)
-                #        if isinstance(opcode, op):
-                #            result = opcode.eval(ctx, stack)
-                #            assert result is None
-                #            break
-                #else:
-                result = opcode.eval(ctx)
-                assert result is None
+            opcode = self._get_opcode(pc)
+            #if we_are_translated():
+            #    #this is an optimization strategy for translated code
+            #    #on top of cpython it destroys the performance
+            #    #besides, this code might be completely wrong
+            #    for name, op in opcode_unrolling:
+            #        opcode = hint(opcode, deepfreeze=True)
+            #        if isinstance(opcode, op):
+            #            result = opcode.eval(ctx, stack)
+            #            assert result is None
+            #            break
+            #else:
+            result = opcode.eval(ctx)
+            assert result is None
 
-                if isinstance(opcode, BaseJump):
-                    new_pc = opcode.do_jump(ctx, pc)
-                    condition = new_pc < pc
-                    pc = new_pc
-                    if condition:
-                        jitdriver.can_enter_jit(pc=pc, self=self, ctx=ctx, 
to_pop=to_pop)
-                    continue
-                else:
-                    pc += 1
-                if isinstance(opcode, WITH_START):
-                    to_pop += 1
-                elif isinstance(opcode, WITH_END):
-                    to_pop -= 1
-        finally:
-            for i in range(to_pop):
-                ctx.pop_object()
+            if isinstance(opcode, BaseJump):
+                new_pc = opcode.do_jump(ctx, pc)
+                condition = new_pc < pc
+                pc = new_pc
+                if condition:
+                    jitdriver.can_enter_jit(pc=pc, self=self, ctx=ctx)
+                continue
+            else:
+                pc += 1
+
+            if isinstance(opcode, WITH_START):
+                ctx = opcode.newctx
+            elif isinstance(opcode, WITH_END):
+                ctx = ctx.parent
 
         if check_stack:
             ctx.check_stack()
diff --git a/js/jsexecution_context.py b/js/jsexecution_context.py
--- a/js/jsexecution_context.py
+++ b/js/jsexecution_context.py
@@ -1,39 +1,55 @@
-from js.jsobj import RO, Property
-from js.utils import MapDict
+from js.utils import MapDict, StackMixin
 
-class ExecutionContext(object):
+class JSContext(object):
     def __init__(self, parent=None):
         self.values = MapDict()
         self.parent = parent
+        self.ctx_obj = None
 
     def resolve_identifier(self, ctx, identifier):
         try:
-            p = self._identifier_get(identifier)
-            assert isinstance(p, Property)
-            return p.value
+            return self.get_property_value(identifier)
         except KeyError:
             from js.jsobj import W_String
             from js.execution import ThrowException
             raise ThrowException(W_String("ReferenceError: %s is not defined" 
% identifier))
 
+    def get_property_value(self, name):
+        return self._get_property(name).value
+
+    def get_property_flags(self, name):
+        return self._get_property(name).flags
+
+    def _get_property(self,name):
+        from js.jsobj import Property
+        p = self._identifier_get(name)
+        assert isinstance(p, Property)
+        return p
+
     def assign(self, name, value):
+        from js.jsobj import RO, Property
         assert name is not None
         try:
-            p = self._identifier_get(name)
-            assert isinstance(p, Property)
+            p = self._get_property(name)
             if p.flags & RO:
                 return
             p.value = value
         except KeyError:
-            p = Property(identifier, value)
-            self._identifier_set(identifier, p)
+            p = Property(name, value)
+            self._identifier_set(name, p)
 
     def declare_variable(self, identifier):
-        from js.jsobj import w_Undefined, DD
+        from js.jsobj import w_Undefined, DD, Property
         self.values.addname(identifier)
         p = Property(identifier, w_Undefined, flags = DD)
         self._identifier_set_local(identifier, p)
 
+    def get_local_value(self, idx):
+        val = self.values.getindex(idx)
+        if val is None:
+            raise KeyError
+        return val.value
+
     def _identifier_set_local(self, identifier, value):
         self.values.set(identifier, value)
 
@@ -65,3 +81,58 @@
             if self.parent:
                 return self.parent._identifier_get(identifier)
         raise KeyError
+
+    def assign_local(self, idx, value):
+        prop = self.values.getindex(idx)
+        prop.value = value
+
+    def get_global(self):
+        if self.parent:
+            return self.parent.get_global()
+        else:
+            return self.to_context_object()
+
+    def to_context_object(self):
+        from jsobj import W_ContextObject
+        return W_ContextObject(self)
+
+    def put(self, name, value):
+        self.declare_variable(name)
+        self.assign(name, value)
+
+    def delete_identifier(self, name):
+        self.values.delete(name)
+        return True
+
+class ActivationContext(JSContext):
+    def __init__(self, parent, this, args):
+        JSContext.__init__(self, parent)
+
+        if this is not None:
+            self.put('this', this)
+
+        self.put('arguments', args)
+
+class GlobalContext(JSContext, StackMixin):
+    def __init__(self, parent=None):
+        JSContext.__init__(self, parent)
+        StackMixin.__init__(self)
+        # TODO size of gloabl context
+        self.values = MapDict(2048)
+
+class ExecutionContext(JSContext, StackMixin):
+    def __init__(self, parent=None):
+        JSContext.__init__(self, parent)
+        StackMixin.__init__(self)
+
+class WithExecutionContext(ExecutionContext):
+    def __init__(self, parent, obj):
+        ExecutionContext.__init__(self, parent)
+        self.ctx_obj = obj
+        self.stack = parent.stack
+        self.stack_pointer = parent.stack_pointer
+
+    def resolve_identifier(self, ctx, identifier):
+        if self.ctx_obj.HasProperty(identifier):
+            return self.ctx_obj.Get(ctx, identifier);
+        return ExecutionContext.resolve_identifier(self, ctx, identifier)
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -118,6 +118,32 @@
 w_Undefined = W_Undefined()
 w_Null = W_Null()
 
+class W_ContextObject(W_Root):
+    def __init__(self, ctx):
+        self.context = ctx
+
+    def __repr__(self):
+        return '<W_ContextObject (%s)>' % (repr(self.context),)
+
+    def Get(self, ctx, name):
+        try:
+            return self.context.get_property_value(name)
+        except KeyError:
+            from js.jsobj import w_Undefined
+            return w_Undefined
+
+    def Put(self, ctx, P, V, flags = 0):
+        self.context.put(P, V)
+
+    def Delete(self, name):
+        try:
+            from jsobj import DD
+            if self.context.get_property_flags(name) & DD:
+                return False
+            self.context.delete_identifier(name)
+        except KeyError:
+            pass
+        return True
 
 class W_PrimitiveObject(W_Root):
     def __init__(self, ctx=None, Prototype=None, Class='Object',
@@ -130,16 +156,23 @@
         self.Class = Class
         self.callfunc = callfunc
         if callfunc is not None:
-            self.Scope = ctx.scope[:]
+            self.ctx = ctx
         else:
             self.Scope = None
         self.Value = Value
 
+    #@jit.unroll_safe
     def Call(self, ctx, args=[], this=None):
         if self.callfunc is None: # XXX Not sure if I should raise it here
             raise JsTypeError('not a function')
-        act = ActivationObject()
-        newctx = function_context(self.Scope, act, this)
+        from js.jsobj import W_Root
+        assert isinstance(this, W_Root)
+
+        from js.jsexecution_context import ActivationContext, ExecutionContext
+
+        w_Arguments = W_Arguments(self, args)
+        act = ActivationContext(self.ctx, this, w_Arguments)
+        newctx = ExecutionContext(act)
 
         paramn = len(self.callfunc.params)
         for i in range(paramn):
@@ -151,10 +184,6 @@
             newctx.declare_variable(paramname)
             newctx.assign(paramname, value)
 
-        act.Put(ctx, 'this', this)
-        w_Arguments = W_Arguments(self, args)
-        act.Put(ctx, 'arguments', w_Arguments)
-
         val = self.callfunc.run(ctx=newctx)
         return val
 
@@ -577,137 +606,6 @@
     def __repr__(self):
         return 'W_List(%s)' % (self.list_w,)
 
-class ExecutionContext(StackMixin):
-    _virtualizable2_ = ['stack[*]', 'stack_pointer']
-    def __init__(self, scope, this=None, variable=None,
-                    debug=False, jsproperty=None):
-        assert scope is not None
-        self.scope = scope
-        if this is None:
-            self.this = scope[0]
-        else:
-            self.this = this
-        if variable is None:
-            self.variable = self.scope[-1]
-        else:
-            self.variable = variable
-        self.debug = debug
-        if jsproperty is None:
-            #Attribute flags for new vars
-            self.property = Property('',w_Undefined)
-        else:
-            self.property = jsproperty
-        self.local_identifiers = []
-        self.local_values = []
-        StackMixin.__init__(self)
-
-    def __str__(self):
-        return "<ExCtx %s, var: %s>"%(self.scope, self.variable)
-
-    def declare_variable(self, name):
-        self.scope[-1].Put(self, name, w_Undefined, flags = DD)
-        prop = self.scope[-1].propdict[name]
-        self.local_values.append(prop)
-
-    def get_local_value(self, idx):
-        return self.local_values[idx].value
-
-    def get_local_index(self, name):
-        return self.local_identifiers.index(name)
-
-    def assign_local(self, idx, value):
-        self.local_values[idx].value = value
-
-    def delete_local(self, identifier):
-        if identifier in self.local_identifiers:
-            idx = self.get_local_index(identifier)
-            self.local_identifiers[idx] = ''
-            # TODO translator does not like this
-            #self.local_variables[idx] = None
-
-    def assign(self, name, value):
-        assert name is not None
-        for i in range(len(self.scope)-1, -1, -1):
-            obj = self.scope[i]
-            assert isinstance(obj, W_PrimitiveObject)
-            try:
-                P = obj.propdict[name]
-                if P.flags & RO:
-                    return
-                P.value = value
-                return
-            except KeyError:
-                pass
-        self.variable.Put(self, name, value)
-
-    def delete_identifier(self, name):
-        self.delete_local(name)
-        for i in range(len(self.scope)-1, -1, -1):
-            obj = self.scope[i]
-            assert isinstance(obj, W_PrimitiveObject)
-            try:
-                P = obj.propdict[name]
-                if P.flags & DD:
-                    return False
-                del obj.propdict[name]
-                return True
-            except KeyError:
-                pass
-        return False
-
-    def get_global(self):
-        return self.scope[0]
-
-    def push_object(self, obj):
-        """push object into scope stack"""
-        assert isinstance(obj, W_PrimitiveObject)
-        self.scope.append(obj)
-        self.variable = obj
-
-    def pop_object(self):
-        """remove the last pushed object"""
-        return self.scope.pop()
-
-    @jit.unroll_safe
-    def resolve_identifier(self, ctx, identifier):
-        for i in range(len(self.scope)-1, -1, -1):
-            obj = self.scope[i]
-            assert isinstance(obj, W_PrimitiveObject)
-            if obj.HasProperty(identifier):
-                return obj.Get(ctx, identifier)
-        raise ThrowException(W_String("ReferenceError: %s is not defined" % 
identifier))
-
-def global_context(w_global):
-    assert isinstance(w_global, W_PrimitiveObject)
-    ctx = ExecutionContext([w_global],
-                            this = w_global,
-                            variable = w_global,
-                            jsproperty = Property('', w_Undefined, flags = DD))
-    return ctx
-
-def function_context(scope, activation, this=None):
-    newscope = scope[:]
-    ctx = ExecutionContext(newscope,
-                            this = this,
-                            jsproperty = Property('', w_Undefined, flags = DD))
-    ctx.push_object(activation)
-    return ctx
-
-def eval_context(calling_context):
-    ctx = ExecutionContext(calling_context.scope[:],
-                            this = calling_context.this,
-                            variable = calling_context.variable,
-                            jsproperty = Property('', w_Undefined))
-    return ctx
-
-def empty_context():
-    obj = W_Object()
-    ctx = ExecutionContext([obj],
-                            this = obj,
-                            variable = obj,
-                            jsproperty = Property('', w_Undefined))
-    return ctx
-
 class W_Iterator(W_Root):
     def __init__(self, elements_w):
         self.elements_w = elements_w
diff --git a/js/opcodes.py b/js/opcodes.py
--- a/js/opcodes.py
+++ b/js/opcodes.py
@@ -452,7 +452,7 @@
         w_obj.Put(ctx, 'constructor', w_func, flags = jsobj.DE)
         w_func.Put(ctx, 'prototype', w_obj)
         if self.funcobj.name is not None:
-            ctx.scope[-1].Put(ctx, self.funcobj.name, w_func)
+            ctx.put(self.funcobj.name, w_func)
 
     def __repr__(self):
         funcobj = self.funcobj
@@ -495,8 +495,9 @@
         r1 = ctx.pop()
         args = ctx.pop()
         name = r1.ToString(ctx)
+        this = ctx.to_context_object()
         #XXX hack, this should be comming from context
-        ctx.append(common_call(ctx, r1, args, ctx.scope[-1], name))
+        ctx.append(common_call(ctx, r1, args, this, name))
 
 class CALL_METHOD(Opcode):
     def eval(self, ctx):
@@ -530,13 +531,10 @@
             except ThrowException, e:
                 if self.catchfunc is not None:
                     # XXX just copied, I don't know if it's right
-                    obj = W_Object()
-                    obj.Put(ctx, self.catchparam, e.exception)
-                    ctx.push_object(obj)
-                    try:
-                        self.catchfunc.run(ctx)
-                    finally:
-                        ctx.pop_object()
+                    from js.jsexecution_context import ExecutionContext
+                    newctx = ExecutionContext(ctx)
+                    newctx.put(self.catchparam, e.exception)
+                    self.catchfunc.run(newctx)
                 if self.finallyfunc is not None:
                     self.finallyfunc.run(ctx)
                 if not self.catchfunc:
@@ -594,13 +592,17 @@
 # ---------------- with support ---------------------
 
 class WITH_START(Opcode):
+    def __init__(self):
+        self.newctx = None
+
     def eval(self, ctx):
         obj = ctx.pop().ToObject(ctx)
-        ctx.push_object(obj)
+        from js.jsexecution_context import WithExecutionContext
+        self.newctx = WithExecutionContext(ctx, obj)
 
 class WITH_END(Opcode):
     def eval(self, ctx):
-        ctx.pop_object()
+        ctx = ctx.parent
 
 # ------------------ delete -------------------------
 
diff --git a/js/test/jit.py b/js/test/jit.py
--- a/js/test/jit.py
+++ b/js/test/jit.py
@@ -5,7 +5,9 @@
     viewloops = True
 conftest.option = o
 
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+#from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
+
 
 from js import interpreter
 from js.jscode import JsCode, jitdriver
@@ -30,7 +32,7 @@
 
         def interp_w(c):
             jitdriver.set_param("inlining", True)
-            code_val = func.run(ExecutionContext([ctx]))
+            code_val = func.run(jsint.global_context)
         interp_w(1)
         self.meta_interp(interp_w, [6], listcomp=True, backendopt=True, 
listops=True)
 
diff --git a/js/test/test_execution_context.py 
b/js/test/test_execution_context.py
--- a/js/test/test_execution_context.py
+++ b/js/test/test_execution_context.py
@@ -159,3 +159,25 @@
         assert p_foo.value == 0
         assert context._identifier_get_local('foo').value == 42
         assert context.resolve_identifier(ctx, 'foo') == 42
+
+    def test_get_local_value(self):
+        context = ExecutionContext()
+        context.declare_variable('foo')
+        context.declare_variable('bar')
+
+        context.assign('foo', 0)
+        assert context.get_local_value(0) == 0
+
+        context.assign('foo', 42)
+        assert context.get_local_value(0) == 42
+
+        context.assign('bar', 1)
+        assert context.get_local_value(1) == 1
+
+    def test_get_local_value_is_local(self):
+        parent = ExecutionContext()
+        context = ExecutionContext(parent)
+
+        p_foo = Property('foo', 0)
+        parent._identifier_set_local('foo', p_foo)
+        py.test.raises(KeyError, context.get_local_value, 0)
diff --git a/js/test/test_interp.py b/js/test/test_interp.py
--- a/js/test/test_interp.py
+++ b/js/test/test_interp.py
@@ -1,10 +1,11 @@
 import py
 from js import interpreter
 from js.operations import IntNumber, FloatNumber, Position, Plus
-from js.jsobj import W_Object, ExecutionContext, W_Root, w_Null
+from js.jsobj import W_Object, W_Root, w_Null
 from js.execution import ThrowException
 from js.jscode import JsCode, POP
 from js.baseop import AbstractEC
+from js.jsexecution_context import ExecutionContext
 
 def test_simple():
     bytecode = JsCode()
@@ -13,7 +14,7 @@
     bytecode.emit('ADD')
     bytecode.emit('POP')
     func = bytecode.make_js_function()
-    res = func.run(ExecutionContext([W_Object()]), check_stack=False)
+    res = func.run(ExecutionContext(), check_stack=False)
     assert res.ToNumber(None) == 6.0
 
 def assertp(code, prints):
@@ -33,12 +34,12 @@
 
 def assertv(code, value):
     jsint = interpreter.Interpreter()
-    ctx = jsint.w_Global
+    ctx = jsint.global_context
     try:
         bytecode = JsCode()
         interpreter.load_source(code, '').emit(bytecode)
         func = bytecode.make_js_function()
-        code_val = func.run(ExecutionContext([ctx]))
+        code_val = func.run(ctx)
     except ThrowException, excpt:
         code_val = excpt.exception
     print code_val, value
diff --git a/js/test/test_parser.py b/js/test/test_parser.py
--- a/js/test/test_parser.py
+++ b/js/test/test_parser.py
@@ -7,7 +7,7 @@
 from pypy import conftest
 
 from js.astbuilder import FakeParseError
-from js.jsobj import W_Object, global_context, ThrowException, empty_context
+from js.jsobj import W_Object, ThrowException
 from js.astbuilder import ASTBuilder
 from js.jscode import JsCode
 import sys
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to