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