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