Author: Stephan <[email protected]>
Branch: 
Changeset: r128:0e94e19ec54b
Date: 2011-09-18 16:22 +0200
http://bitbucket.org/pypy/lang-js/changeset/0e94e19ec54b/

Log:    estimate stack size

diff --git a/js/jscode.py b/js/jscode.py
--- a/js/jscode.py
+++ b/js/jscode.py
@@ -32,6 +32,15 @@
         from js.astbuilder import Scope
         self.scope = Scope()
 
+    def estimated_stack_size(self):
+        max_size = 0
+        moving_size = 0
+        for opcode in self.opcodes:
+            moving_size += opcode.stack_change()
+            max_size = max(moving_size, max_size)
+        assert max_size >= 0
+        return max_size
+
     def emit_label(self, num = -1):
         if num == -1:
             num = self.prealocate_label()
@@ -163,8 +172,11 @@
         self.opcodes = make_sure_not_resized(code.opcodes[:])
         self.scope = code.scope
 
+    def estimated_stack_size(self):
+        return self.code.estimated_stack_size()
+
     def run(self, ctx, check_stack=True):
-        state = _save_stack(ctx, len(self.opcodes) * 2)
+        state = _save_stack(ctx, self.estimated_stack_size())
 
         try:
             r = self.run_bytecode(ctx, check_stack)
diff --git a/js/opcodes.py b/js/opcodes.py
--- a/js/opcodes.py
+++ b/js/opcodes.py
@@ -9,6 +9,7 @@
 from pypy.rlib.rarithmetic import intmask
 
 class Opcode(object):
+    _stack_change = 1
     def __init__(self):
         pass
 
@@ -17,10 +18,14 @@
         """
         raise NotImplementedError
 
+    def stack_change(self):
+        return self._stack_change
+
     def __repr__(self):
         return self.__class__.__name__
 
 class BaseBinaryComparison(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         s4 = ctx.pop()
         s2 = ctx.pop()
@@ -30,6 +35,7 @@
         raise NotImplementedError
 
 class BaseBinaryBitwiseOp(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         s5 = ctx.pop().ToInt32(ctx)
         s6 = ctx.pop().ToInt32(ctx)
@@ -39,13 +45,14 @@
         raise NotImplementedError
 
 class BaseBinaryOperation(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         right = ctx.pop()
         left = ctx.pop()
         ctx.append(self.operation(ctx, left, right))
 
 class BaseUnaryOperation(Opcode):
-    pass
+    _stack_change = 0
 
 class Undefined(Opcode):
     def eval(self, ctx):
@@ -138,6 +145,9 @@
             array.Put(ctx, str(self.counter - i - 1), ctx.pop())
         ctx.append(array)
 
+    def stack_change(self):
+        return -1 * self.counter + 1
+
     def __repr__(self):
         return 'LOAD_ARRAY %d' % (self.counter,)
 
@@ -150,6 +160,9 @@
         list_w = ctx.pop_n(self.counter)[:] # pop_n returns a non-resizable 
list
         ctx.append(W_List(list_w))
 
+    def stack_change(self):
+        return -1 * self.counter + 1
+
     def __repr__(self):
         return 'LOAD_LIST %d' % (self.counter,)
 
@@ -198,6 +211,7 @@
         return 'LOAD_OBJECT %d' % (self.counter,)
 
 class LOAD_MEMBER(Opcode):
+    _stack_change = -1
     def eval(self, ctx):
         w_obj = ctx.pop().ToObject(ctx)
         name = ctx.pop().ToString(ctx)
@@ -357,6 +371,7 @@
         return newbool(not StrictEC(ctx, op1, op2))
 
 class STORE_MEMBER(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         left = ctx.pop()
         member = ctx.pop()
@@ -367,6 +382,7 @@
 
 class STORE(Opcode):
     _immutable_fields_ = ['name']
+    _stack_change = 0
     def __init__(self, name):
         self.name = name
 
@@ -378,6 +394,7 @@
         return '%s "%s"' % (self.__class__.__name__, self.name)
 
 class LABEL(Opcode):
+    _stack_change = 0
     def __init__(self, num):
         self.num = num
 
@@ -386,6 +403,7 @@
 
 class BaseJump(Opcode):
     _immutable_fields_ = ['where']
+    _stack_change = 0
     def __init__(self, where):
         self.where = where
         self.decision = False
@@ -440,6 +458,7 @@
         return pos + 1
 
 class DECLARE_FUNCTION(Opcode):
+    _stack_change = 0
     def __init__(self, funcobj):
         self.funcobj = funcobj
 
@@ -464,6 +483,7 @@
         return 'DECLARE_FUNCTION %s%r [\n%s\n]' % (name, funcobj.params, 
codestr)
 
 class DECLARE_VAR(Opcode):
+    _stack_change = 0
     def __init__(self, name):
         self.name = name
 
@@ -474,10 +494,12 @@
         return 'DECLARE_VAR "%s"' % (self.name,)
 
 class RETURN(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         raise ReturnException(ctx.pop())
 
 class POP(Opcode):
+    _stack_change = -1
     def eval(self, ctx):
         ctx.pop()
 
@@ -491,6 +513,7 @@
     return res
 
 class CALL(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         r1 = ctx.pop()
         args = ctx.pop()
@@ -500,6 +523,7 @@
         ctx.append(common_call(ctx, r1, args, this, name))
 
 class CALL_METHOD(Opcode):
+    _stack_change = -2
     def eval(self, ctx):
         method = ctx.pop()
         what = ctx.pop().ToObject(ctx)
@@ -513,11 +537,13 @@
         ctx.append(ctx.top())
 
 class THROW(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         val = ctx.pop()
         raise ThrowException(val)
 
 class TRYCATCHBLOCK(Opcode):
+    _stack_change = 0
     def __init__(self, tryfunc, catchparam, catchfunc, finallyfunc):
         self.tryfunc     = tryfunc
         self.catchfunc   = catchfunc
@@ -548,6 +574,7 @@
         return "TRYCATCHBLOCK" # XXX shall we add stuff here???
 
 class NEW(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         y = ctx.pop()
         x = ctx.pop()
@@ -556,6 +583,7 @@
         ctx.append(commonnew(ctx, x, args))
 
 class NEW_NO_ARGS(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         x = ctx.pop()
         ctx.append(commonnew(ctx, x, []))
@@ -563,6 +591,7 @@
 # ------------ iterator support ----------------
 
 class LOAD_ITERATOR(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         obj = ctx.pop().ToObject(ctx)
         props = [prop.value for prop in obj.propdict.values() if not 
prop.flags & jsobj.DE]
@@ -580,6 +609,7 @@
         return pos + 1
 
 class NEXT_ITERATOR(Opcode):
+    _stack_change = 0
     def __init__(self, name):
         self.name = name
 
@@ -591,6 +621,7 @@
 # ---------------- with support ---------------------
 
 class WITH_START(Opcode):
+    _stack_change = 0
     def __init__(self):
         self.newctx = None
 
@@ -600,6 +631,7 @@
         self.newctx = WithExecutionContext(ctx, obj)
 
 class WITH_END(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         ctx = ctx.parent
 
@@ -613,6 +645,7 @@
         ctx.append(newbool(ctx.delete_identifier(self.name)))
 
 class DELETE_MEMBER(Opcode):
+    _stack_change = 0
     def eval(self, ctx):
         what = ctx.pop().ToString(ctx)
         obj = ctx.pop().ToObject(ctx)
@@ -630,6 +663,7 @@
         return 'LOAD_LOCAL %d' % (self.local,)
 
 class STORE_LOCAL(Opcode):
+    _stack_change = 0
     _immutable_fields_ = ['local']
     def __init__(self, local):
         self.local = local
diff --git a/js/test/test_jscode.py b/js/test/test_jscode.py
new file mode 100644
--- /dev/null
+++ b/js/test/test_jscode.py
@@ -0,0 +1,32 @@
+import py
+
+def assert_code_size(*args):
+    from js.jscode import JsCode
+    b = JsCode()
+    size = args[-1]
+
+    for bytecode in args[:-1]:
+        if type(bytecode) == tuple:
+            a = bytecode
+        else:
+            a = (bytecode,)
+        b.emit(*a)
+
+    assert b.estimated_stack_size() == size
+
+class TestJsCodeSizeEstimation(object):
+    def test_estimate_size_empty_code(self):
+        assert_code_size(0)
+
+    def test_estimate_size(self):
+        yield assert_code_size, ('LOAD_INTCONSTANT', 1), 'POP', 1
+        yield assert_code_size, ('LOAD_INTCONSTANT', 1), 'POP', 'POP', 1
+        yield assert_code_size, ('LOAD_INTCONSTANT', 1), ('LOAD_INTCONSTANT', 
2), 'ADD', 2
+        yield assert_code_size, ('LOAD_LIST', 5), 0
+        yield assert_code_size, ('LOAD_ARRAY', 5), 0
+        yield assert_code_size, ('LOAD_LOCAL', 1), ('LOAD_LOCAL', 1), 
('LOAD_LOCAL', 1), ('LOAD_ARRAY', 3), 3
+        yield assert_code_size,\
+            ('LOAD_LOCAL', 1), ('LOAD_LOCAL', 1), ('LOAD_LOCAL', 1),\
+            ('LOAD_ARRAY', 3),\
+            ('LOAD_LOCAL', 1), ('LOAD_LOCAL', 1), ('LOAD_LOCAL', 1), 
('LOAD_LOCAL', 1),\
+            5
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to