[pypy-svn] r52371 - in pypy/branch/jit-refactoring/pypy/lang/js: . bench test test/ecma
fijal at codespeak.net
fijal at codespeak.net
Tue Mar 11 10:42:56 CET 2008
Author: fijal
Date: Tue Mar 11 10:42:56 2008
New Revision: 52371
Added:
pypy/branch/jit-refactoring/pypy/lang/js/bench/
pypy/branch/jit-refactoring/pypy/lang/js/bench/f1.js
pypy/branch/jit-refactoring/pypy/lang/js/execution.py (contents, props changed)
pypy/branch/jit-refactoring/pypy/lang/js/test/test_frames.py (contents, props changed)
pypy/branch/jit-refactoring/pypy/lang/js/test/test_numbers.py (contents, props changed)
pypy/branch/jit-refactoring/pypy/lang/js/test_scope.py (contents, props changed)
Modified:
pypy/branch/jit-refactoring/pypy/lang/js/astbuilder.py
pypy/branch/jit-refactoring/pypy/lang/js/interpreter.py
pypy/branch/jit-refactoring/pypy/lang/js/jsobj.py
pypy/branch/jit-refactoring/pypy/lang/js/operations.py
pypy/branch/jit-refactoring/pypy/lang/js/test/ecma/conftest.py
pypy/branch/jit-refactoring/pypy/lang/js/test/test_interp.py
pypy/branch/jit-refactoring/pypy/lang/js/test/test_operations.py
Log:
* Refactor number handling to be more efficient (and correct)
* (in-progress) Refactor scope handling
* Some tests
* Generl progress
Modified: pypy/branch/jit-refactoring/pypy/lang/js/astbuilder.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/astbuilder.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/astbuilder.py Tue Mar 11 10:42:56 2008
@@ -80,18 +80,19 @@
def visit_DECIMALLITERAL(self, node):
pos = self.get_pos(node)
- number = operations.Number(pos, float(node.additional_info))
- return number
+ try:
+ int(node.additional_info)
+ except ValueError:
+ return operations.FloatNumber(pos, float(node.additional_info))
+ return operations.IntNumber(pos, int(node.additional_info))
def visit_HEXINTEGERLITERAL(self, node):
pos = self.get_pos(node)
- number = operations.Number(pos, float(int(node.additional_info, 16)))
- return number
+ return operations.IntNumber(pos, int(node.additional_info, 16))
def visit_OCTALLITERAL(self, node):
pos = self.get_pos(node)
- number = operations.Number(pos, float(int(node.additional_info, 8)))
- return number
+ return operations.IntNumber(pos, int(node.additional_info, 8))
def string(self,node):
pos = self.get_pos(node)
@@ -395,4 +396,4 @@
identifier = self.dispatch(node.children[0])
body = self.dispatch(node.children[1])
return operations.With(pos, identifier, body)
-
\ No newline at end of file
+
Added: pypy/branch/jit-refactoring/pypy/lang/js/bench/f1.js
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/lang/js/bench/f1.js Tue Mar 11 10:42:56 2008
@@ -0,0 +1,22 @@
+
+// some simple number-crunching benchmarks
+
+function f1(n) {
+ var i = 0;
+ var x = 1;
+ while (i < n) {
+ var j = 0;
+ while (j <= i) {
+ j++;
+ x = x + (i&j);
+ }
+ i++;
+ }
+ return x;
+}
+
+a = new Date();
+f1(2117);
+b = new Date();
+print(b - a);
+
Added: pypy/branch/jit-refactoring/pypy/lang/js/execution.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/lang/js/execution.py Tue Mar 11 10:42:56 2008
@@ -0,0 +1,26 @@
+
+class JsBaseExcept(Exception):
+ pass
+
+#XXX Just an idea for now
+class JsRuntimeExcept(Exception):
+ def __init__(self, pos, message, exception_object):
+ self.pos = pos
+ self.message = message
+ self.exception_object = exception_object # JS Exception Object
+
+class ExecutionReturned(JsBaseExcept):
+ def __init__(self, type='normal', value=None, identifier=None):
+ self.type = type
+ self.value = value
+ self.identifier = identifier
+
+class ThrowException(JsBaseExcept):
+ def __init__(self, exception):
+ self.exception = exception
+ self.args = [exception]
+
+class JsTypeError(JsBaseExcept):
+ pass
+
+class RangeError(JsBaseExcept): pass
Modified: pypy/branch/jit-refactoring/pypy/lang/js/interpreter.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/interpreter.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/interpreter.py Tue Mar 11 10:42:56 2008
@@ -2,8 +2,11 @@
import math
from pypy.lang.js.jsparser import parse, ParseError
from pypy.lang.js.astbuilder import ASTBuilder
-from pypy.lang.js.operations import *
-from pypy.lang.js.jsobj import ThrowException
+from pypy.lang.js.jsobj import global_context, W_Object,\
+ w_Undefined, W_NewBuiltin, W_IntNumber, w_Null, create_object, W_Boolean,\
+ W_FloatNumber, NaN, Infinity, W_String, W_Builtin, W_Array, w_Null,\
+ isnull_or_undefined, W_PrimitiveObject, W_ListObject
+from pypy.lang.js.execution import ThrowException, JsTypeError
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.streamio import open_file_as_stream
@@ -37,8 +40,8 @@
return self.Construct(ctx)
def Construct(self, ctx, args=[]):
- if len(args) >= 1 and not (isinstance(args[0], W_Undefined) \
- or isinstance(args[0], W_Null)):
+ if (len(args) >= 1 and not args[0] is w_Undefined and not
+ args[0] is w_Null):
# XXX later we could separate builtins and normal objects
return args[0].ToObject(ctx)
return create_object(ctx, 'Object')
@@ -59,15 +62,15 @@
class W_NumberObject(W_NativeObject):
def Call(self, ctx, args=[], this=None):
if len(args) >= 1 and not isnull_or_undefined(args[0]):
- return W_Number(args[0].ToNumber())
+ return W_FloatNumber(args[0].ToNumber())
else:
- return W_Number(0.0)
+ return W_FloatNumber(0.0)
def Construct(self, ctx, args=[]):
if len(args) >= 1 and not isnull_or_undefined(args[0]):
- Value = W_Number(args[0].ToNumber())
+ Value = W_FloatNumber(args[0].ToNumber())
return create_object(ctx, 'Number', Value = Value)
- return create_object(ctx, 'Number', Value = W_Number(0.0))
+ return create_object(ctx, 'Number', Value = W_FloatNumber(0.0))
class W_StringObject(W_NativeObject):
def Call(self, ctx, args=[], this=None):
@@ -87,7 +90,6 @@
proto = ctx.get_global().Get('Array').Get('prototype')
array = W_Array(ctx, Prototype=proto, Class = proto.Class)
for i in range(len(args)):
- print "yeahh"
array.Put(str(i), args[0])
return array
@@ -119,7 +121,7 @@
def parseIntjs(ctx, args, this):
if len(args) < 1:
- return W_Number(NaN)
+ return W_FloatNumber(NaN)
s = args[0].ToString(ctx).strip(" ")
if len(args) > 1:
radix = args[1].ToInt32()
@@ -129,22 +131,22 @@
radix = 16
s = s[2:]
if s == '' or radix < 2 or radix > 36:
- return W_Number(NaN)
+ return W_FloatNumber(NaN)
try:
n = int(s, radix)
except ValueError:
- n = NaN
- return W_Number(n)
+ return W_FloatNumber(NaN)
+ return W_IntNumber(n)
def parseFloatjs(ctx, args, this):
if len(args) < 1:
- return W_Number(NaN)
+ return W_FloatNumber(NaN)
s = args[0].ToString(ctx).strip(" ")
try:
n = float(s)
except ValueError:
n = NaN
- return W_Number(n)
+ return W_FloatNumber(n)
def printjs(ctx, args, this):
@@ -184,20 +186,25 @@
def numberjs(ctx, args, this):
if len(args) > 0:
- return W_Number(args[0].ToNumber())
- return W_Number(0)
+ return W_FloatNumber(args[0].ToNumber())
+ return W_IntNumber(0)
def absjs(ctx, args, this):
- return W_Number(abs(args[0].ToNumber()))
+ val = args[0]
+ if isinstance(val, W_IntNumber):
+ if val.intval > 0:
+ return val # fast path
+ return W_IntNumber(-val.intval)
+ return W_FloatNumber(abs(args[0].ToNumber()))
def floorjs(ctx, args, this):
- return W_Number(math.floor(args[0].ToNumber()))
+ return W_IntNumber(int(math.floor(args[0].ToNumber())))
def powjs(ctx, args, this):
- return W_Number(math.pow(args[0].ToNumber(), args[1].ToNumber()))
+ return W_FloatNumber(math.pow(args[0].ToNumber(), args[1].ToNumber()))
def sqrtjs(ctx, args, this):
- return W_Number(math.sqrt(args[0].ToNumber()))
+ return W_FloatNumber(math.sqrt(args[0].ToNumber()))
def versionjs(ctx, args, this):
return w_Undefined
@@ -280,8 +287,7 @@
arrayArgs = args[1]
if isinstance(arrayArgs, W_ListObject):
callargs = arrayArgs.tolist()
- elif isinstance(arrayArgs, W_Undefined) \
- or isinstance(arrayArgs, W_Null):
+ elif isnull_or_undefined(arrayArgs):
callargs = []
else:
raise JsTypeError('arrayArgs is not an Array or Arguments object')
@@ -334,7 +340,7 @@
def Call(self, ctx, args=[], this=None):
string = this.ToString(ctx)
if len(args) < 1:
- return W_Number(-1.0)
+ return W_IntNumber(-1)
substr = args[0].ToString(ctx)
size = len(string)
subsize = len(substr)
@@ -343,7 +349,7 @@
else:
pos = args[1].ToInt32()
pos = min(max(pos, 0), size)
- return W_Number(string.find(substr, pos))
+ return W_IntNumber(string.find(substr, pos))
class W_Substring(W_NewBuiltin):
def Call(self, ctx, args=[], this=None):
@@ -377,6 +383,9 @@
def Construct(self, ctx, args=[]):
return create_object(ctx, 'Object')
+def pypy_repr(ctx, repr, w_arg):
+ return W_String(w_arg.__class__.__name__)
+
class Interpreter(object):
"""Creates a js interpreter"""
def __init__(self):
@@ -403,7 +412,7 @@
w_Function.Put('prototype', w_FncPrototype, dd=True, de=True, ro=True)
w_Function.Put('constructor', w_Function)
- w_Object.Put('length', W_Number(1), ro=True, dd=True)
+ w_Object.Put('length', W_IntNumber(1), ro=True, dd=True)
toString = W_ToString(ctx)
@@ -447,7 +456,7 @@
#Number
w_Number = W_NumberObject('Number', w_FncPrototype)
- w_NumPrototype = create_object(ctx, 'Object', Value=W_Number(0.0))
+ w_NumPrototype = create_object(ctx, 'Object', Value=W_FloatNumber(0.0))
w_NumPrototype.Class = 'Number'
put_values(w_NumPrototype, {
'constructor': w_FncPrototype,
@@ -459,9 +468,9 @@
put_values(w_Number, {
'constructor': w_FncPrototype,
'prototype': w_NumPrototype,
- 'NaN': W_Number(NaN),
- 'POSITIVE_INFINITY': W_Number(Infinity),
- 'NEGATIVE_INFINITY': W_Number(-Infinity),
+ 'NaN': W_FloatNumber(NaN),
+ 'POSITIVE_INFINITY': W_FloatNumber(Infinity),
+ 'NEGATIVE_INFINITY': W_FloatNumber(-Infinity),
})
w_Global.Put('Number', w_Number)
@@ -511,8 +520,8 @@
w_math.Put('floor', W_Builtin(floorjs, Class='function'))
w_math.Put('pow', W_Builtin(powjs, Class='function'))
w_math.Put('sqrt', W_Builtin(sqrtjs, Class='function'))
- w_math.Put('E', W_Number(math.e))
- w_math.Put('PI', W_Number(math.pi))
+ w_math.Put('E', W_FloatNumber(math.e))
+ w_math.Put('PI', W_FloatNumber(math.pi))
w_Global.Put('version', W_Builtin(versionjs))
@@ -520,8 +529,8 @@
w_Date = W_DateFake(ctx, Class='Date')
w_Global.Put('Date', w_Date)
- w_Global.Put('NaN', W_Number(NaN))
- w_Global.Put('Infinity', W_Number(Infinity))
+ w_Global.Put('NaN', W_FloatNumber(NaN))
+ w_Global.Put('Infinity', W_FloatNumber(Infinity))
w_Global.Put('undefined', w_Undefined)
w_Global.Put('eval', W_Builtin(evaljs))
w_Global.Put('parseInt', W_Builtin(parseIntjs))
@@ -531,7 +540,10 @@
w_Global.Put('print', W_Builtin(printjs))
w_Global.Put('this', w_Global)
-
+
+ # DEBUGGING
+ if 1:
+ w_Global.Put('pypy_repr', W_Builtin(pypy_repr))
self.global_context = ctx
self.w_Global = w_Global
@@ -549,9 +561,12 @@
res.append(arg)
elif isinstance(arg, str):
res.append(W_String(arg))
- elif isinstance(arg, int) or isinstance(arg, float) \
- or isinstance(arg, long):
- res.append(W_Number(arg))
+ elif isinstance(arg, int):
+ res.append(W_IntNumber(arg))
+ elif isinstance(arg, float):
+ res.append(W_FloatNumber(arg))
elif isinstance(arg, bool):
res.append(W_Boolean(arg))
- return res
\ No newline at end of file
+ else:
+ raise Exception("Cannot wrap %s" % (arg,))
+ return res
Modified: pypy/branch/jit-refactoring/pypy/lang/js/jsobj.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/jsobj.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/jsobj.py Tue Mar 11 10:42:56 2008
@@ -1,36 +1,12 @@
# encoding: utf-8
-from pypy.rlib.rarithmetic import r_uint, intmask
-
+from pypy.rlib.rarithmetic import r_uint, intmask, isnan, isinf,\
+ ovfcheck_float_to_int
+from pypy.lang.js.execution import ThrowException, JsTypeError,\
+ ExecutionReturned, RangeError
class SeePage(NotImplementedError):
pass
-class JsBaseExcept(Exception):
- pass
-
-#XXX Just an idea for now
-class JsRuntimeExcept(Exception):
- def __init__(self, pos, message, exception_object):
- self.pos = pos
- self.message = message
- self.exception_object = exception_object # JS Exception Object
-
-class ExecutionReturned(JsBaseExcept):
- def __init__(self, type='normal', value=None, identifier=None):
- self.type = type
- self.value = value
- self.identifier = identifier
-
-class ThrowException(JsBaseExcept):
- def __init__(self, exception):
- self.exception = exception
- self.args = [exception]
-
-class JsTypeError(JsBaseExcept):
- pass
-
-class RangeError(JsBaseExcept): pass
-
Infinity = 1e300 * 1e300
NaN = Infinity/Infinity
@@ -312,7 +288,7 @@
W_PrimitiveObject.__init__(self, Class='Arguments')
del self.propdict["prototype"]
self.Put('callee', callee)
- self.Put('length', W_Number(len(args)))
+ self.Put('length', W_IntNumber(len(args)))
for i in range(len(args)):
self.Put(str(i), args[i])
self.length = len(args)
@@ -330,7 +306,7 @@
def __init__(self, ctx=None, Prototype=None, Class='Array',
Value=w_Undefined, callfunc=None):
W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, callfunc)
- self.Put('length', W_Number(0))
+ self.Put('length', W_IntNumber(0))
self.length = r_uint(0)
def Put(self, P, V, dd=False,
@@ -343,7 +319,7 @@
res = V.ToUInt32()
if V.ToNumber() < 0:
raise RangeError()
- self.propdict['length'].value = W_Number(res)
+ self.propdict['length'].value = W_IntNumber(res)
self.length = res
return
except ValueError:
@@ -355,14 +331,14 @@
dd = dd, ro = ro, it = it)
try:
- index = r_uint(float(P))
+ index = r_uint(int(P))
except ValueError:
return
if index < self.length:
return
- self.length = index+1
- self.propdict['length'].value = W_Number(index+1)
+ self.length = index+1
+ self.propdict['length'].value = W_IntNumber(index+1)
return
@@ -414,71 +390,87 @@
def GetPropertyName(self):
return self.ToString()
-class W_Number(W_Primitive):
+class W_BaseNumber(W_Primitive):
+ """ Base class for numbers, both known to be floats
+ and those known to be integers
+ """
+ def ToObject(self, ctx):
+ return create_object(ctx, 'Number', Value=self)
+
+ def Get(self, name):
+ return w_Undefined
+
+ def type(self):
+ return 'number'
+
+class W_IntNumber(W_BaseNumber):
+ """ Number known to be an integer
+ """
+ def __init__(self, intval):
+ self.intval = intmask(intval)
+
+ def __str__(self):
+ return str(self.intval)+"W"
+
+ def ToString(self, ctx=None):
+ return str(self.intval)
+
+ def ToBoolean(self):
+ return bool(self.intval)
+
+ def ToNumber(self):
+ # XXX
+ return float(self.intval)
+
+ def ToInt32(self):
+ return self.intval
+
+ def ToUInt32(self):
+ return r_uint(self.intval)
+
+ def GetPropertyName(self):
+ return self.ToString()
+
+class W_FloatNumber(W_BaseNumber):
+ """ Number known to be a float
+ """
def __init__(self, floatval):
- try:
- self.floatval = float(floatval)
- except OverflowError:
- # XXX this should not be happening, there is an error somewhere else
- #an ecma test to stress this is GlobalObject/15.1.2.2-2.js
- self.floatval = Infinity
+ self.floatval = floatval
def __str__(self):
return str(self.floatval)+"W"
-
- def ToObject(self, ctx):
- return create_object(ctx, 'Number', Value=self)
-
+
def ToString(self, ctx = None):
- floatstr = str(self.floatval)
- if floatstr == str(NaN):
+ if isnan(self.floatval):
return 'NaN'
- if floatstr == str(Infinity):
- return 'Infinity'
- if floatstr == str(-Infinity):
- return '-Infinity'
+ if isinf(self.floatval):
+ if self.floatval > 0:
+ return 'Infinity'
+ else:
+ return '-Infinity'
try:
- if float(int(self.floatval)) == self.floatval:
- return str(int(self.floatval))
- except OverflowError, e:
- pass
- return floatstr
+ return str(ovfcheck_float_to_int(self.floatval))
+ except OverflowError:
+ return str(self.floatval)
def ToBoolean(self):
- if self.floatval == 0.0 or str(self.floatval) == str(NaN):
+ if isnan(self.floatval):
return False
return bool(self.floatval)
def ToNumber(self):
return self.floatval
-
- def Get(self, name):
- return w_Undefined
-
- def type(self):
- return 'number'
-
+
def ToInt32(self):
- strval = str(self.floatval)
- if strval == str(NaN) or \
- strval == str(Infinity) or \
- strval == str(-Infinity):
- return 0
-
+ if isnan(self.floatval) or isinf(self.floatval):
+ return 0
return int(self.floatval)
def ToUInt32(self):
- strval = str(self.floatval)
- if strval == str(NaN) or \
- strval == str(Infinity) or \
- strval == str(-Infinity):
+ if isnan(self.floatval) or isinf(self.floatval):
return r_uint(0)
-
return r_uint(self.floatval)
-
- def GetPropertyName(self):
- return self.ToString()
-
+
class W_List(W_Root):
def __init__(self, list_w):
self.list_w = list_w
@@ -496,15 +488,25 @@
return str(self.list_w)
class ExecutionContext(object):
+ def create_fast_lookup(self, scope_elem):
+ fast_lookup = {}
+ for elem, val in self.scope[-1].propdict.iteritems():
+ if val.dd:
+ fast_lookup[elem] = W_Reference(elem, self.scope[-1])
+ return fast_lookup
+
def __init__(self, scope, this=None, variable=None,
debug=False, jsproperty=None):
assert scope is not None
+ assert len(scope) == 1
self.scope = scope
if this is None:
self.this = scope[-1]
else:
self.this = this
-
+ self.fast_lookup = self.create_fast_lookup(scope[-1])
+ self.scope_lookup = [self.fast_lookup]
+ # create a fast lookup
if variable is None:
self.variable = self.scope[0]
else:
@@ -528,14 +530,23 @@
def push_object(self, obj):
"""push object into scope stack"""
assert isinstance(obj, W_PrimitiveObject)
+ # XXX O(n^2)
self.scope.insert(0, obj)
self.variable = obj
+ self.fast_lookup = self.create_fast_lookup(obj)
+ self.scope_lookup.append(self.fast_lookup)
def pop_object(self):
"""remove the last pushed object"""
+ self.scope_lookup.pop()
+ self.fast_lookup = self.scope_lookup[-1]
return self.scope.pop(0)
def resolve_identifier(self, identifier):
+ try:
+ return self.fast_lookup[identifier]
+ except KeyError:
+ pass
for obj in self.scope:
assert isinstance(obj, W_PrimitiveObject)
if obj.HasProperty(identifier):
@@ -559,7 +570,7 @@
jsproperty = Property('', w_Undefined, dd=True))
ctx.push_object(activation)
return ctx
-
+
def eval_context(calling_context):
ctx = ExecutionContext(calling_context.scope[:],
this = calling_context.this,
@@ -611,7 +622,6 @@
return obj
def isnull_or_undefined(obj):
- if isinstance(obj, W_Undefined) or isinstance(obj, W_Null):
+ if obj is w_Null or obj is w_Undefined:
return True
- else:
- return False
+ return False
Modified: pypy/branch/jit-refactoring/pypy/lang/js/operations.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/operations.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/operations.py Tue Mar 11 10:42:56 2008
@@ -4,10 +4,15 @@
Implements the javascript operations nodes for the interpretation tree
"""
-#XXX * imports are bad
-from pypy.lang.js.jsobj import *
+from pypy.lang.js.jsobj import W_IntNumber, W_FloatNumber, W_Object,\
+ w_Undefined, W_NewBuiltin, W_String, create_object, W_List,\
+ W_PrimitiveObject, W_Reference, ActivationObject, W_Array, W_Boolean,\
+ w_Null, W_BaseNumber, isnull_or_undefined
from pypy.rlib.parsing.ebnfparse import Symbol, Nonterminal
-from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.rarithmetic import r_uint, intmask, INFINITY, NAN, ovfcheck,\
+ isnan, isinf
+from pypy.lang.js.execution import ExecutionReturned, JsTypeError,\
+ ThrowException
from constants import unescapedict, SLASH
import sys
@@ -139,11 +144,11 @@
elif op == "%=":
val = mod(ctx, v1.GetValue(), v3)
elif op == "&=":
- val = W_Number(v1.GetValue().ToInt32() & v3.ToInt32())
+ val = W_IntNumber(v1.GetValue().ToInt32() & v3.ToInt32())
elif op == "|=":
- val = W_Number(v1.GetValue().ToInt32() | v3.ToInt32())
+ val = W_IntNumber(v1.GetValue().ToInt32() | v3.ToInt32())
elif op == "^=":
- val = W_Number(v1.GetValue().ToInt32() ^ v3.ToInt32())
+ val = W_IntNumber(v1.GetValue().ToInt32() ^ v3.ToInt32())
else:
print op
raise NotImplementedError()
@@ -172,24 +177,24 @@
class BitwiseAnd(BinaryBitwiseOp):
def decision(self, ctx, op1, op2):
- return W_Number(op1&op2)
+ return W_IntNumber(op1&op2)
class BitwiseNot(UnaryOp):
def eval(self, ctx):
op1 = self.expr.eval(ctx).GetValue().ToInt32()
- return W_Number(~op1)
+ return W_IntNumber(~op1)
class BitwiseOr(BinaryBitwiseOp):
def decision(self, ctx, op1, op2):
- return W_Number(op1|op2)
+ return W_IntNumber(op1|op2)
class BitwiseXor(BinaryBitwiseOp):
def decision(self, ctx, op1, op2):
- return W_Number(op1^op2)
+ return W_IntNumber(op1^op2)
class Unconditional(Statement):
@@ -224,7 +229,6 @@
r7 = None
else:
r7 = r6
-
try:
res = r3.Call(ctx=ctx, args=r2.get_args(), this=r7)
except JsTypeError:
@@ -277,7 +281,7 @@
def eval(self, ctx):
proto = ctx.get_global().Get('Function').Get('prototype')
w_func = W_Object(ctx=ctx, Prototype=proto, Class='Function', callfunc=self)
- w_func.Put('length', W_Number(len(self.params)))
+ w_func.Put('length', W_IntNumber(len(self.params)))
w_obj = create_object(ctx, 'Object')
w_obj.Put('constructor', w_func, de=True)
w_func.Put('prototype', w_obj)
@@ -332,12 +336,13 @@
Implements the Abstract Relational Comparison x < y
Still not fully to the spec
"""
+ # XXX fast path when numbers only
s1 = x.ToPrimitive(ctx, 'Number')
s2 = y.ToPrimitive(ctx, 'Number')
if not (isinstance(s1, W_String) and isinstance(s2, W_String)):
s4 = s1.ToNumber()
s5 = s2.ToNumber()
- if s4 == NaN or s5 == NaN:
+ if isnan(s4) or isnan(s5):
return -1
if s4 < s5:
return 1
@@ -416,19 +421,19 @@
def decision(self, ctx, op1, op2):
a = op1.ToUInt32()
b = op2.ToUInt32()
- return W_Number(a >> (b & 0x1F))
+ return W_IntNumber(a >> (b & 0x1F))
class Rsh(BinaryComparisonOp):
def decision(self, ctx, op1, op2):
a = op1.ToInt32()
b = op2.ToUInt32()
- return W_Number(a >> intmask(b & 0x1F))
+ return W_IntNumber(a >> intmask(b & 0x1F))
class Lsh(BinaryComparisonOp):
def decision(self, ctx, op1, op2):
a = op1.ToInt32()
b = op2.ToUInt32()
- return W_Number(a << intmask(b & 0x1F))
+ return W_IntNumber(a << intmask(b & 0x1F))
##############################################################################
#
@@ -442,6 +447,7 @@
Implements the Abstract Equality Comparison x == y
trying to be fully to the spec
"""
+ # XXX think about fast paths here and there
type1 = x.type()
type2 = y.type()
if type1 == type2:
@@ -450,8 +456,7 @@
if type1 == "number":
n1 = x.ToNumber()
n2 = y.ToNumber()
- nan_string = str(NaN)
- if str(n1) == nan_string or str(n2) == nan_string:
+ if isnan(n1) or isnan(n2):
return False
if n1 == n2:
return True
@@ -467,13 +472,13 @@
(type1 == "null" and type2 == "undefined"):
return True
if type1 == "number" and type2 == "string":
- return AEC(ctx, x, W_Number(y.ToNumber()))
+ return AEC(ctx, x, W_FloatNumber(y.ToNumber()))
if type1 == "string" and type2 == "number":
- return AEC(ctx, W_Number(x.ToNumber()), y)
+ return AEC(ctx, W_FloatNumber(x.ToNumber()), y)
if type1 == "boolean":
- return AEC(ctx, W_Number(x.ToNumber()), y)
+ return AEC(ctx, W_FloatNumber(x.ToNumber()), y)
if type2 == "boolean":
- return AEC(ctx, x, W_Number(y.ToNumber()))
+ return AEC(ctx, x, W_FloatNumber(y.ToNumber()))
if (type1 == "string" or type1 == "number") and \
type2 == "object":
return AEC(ctx, x, y.ToPrimitive(ctx))
@@ -524,8 +529,7 @@
if type1 == "number":
n1 = x.ToNumber()
n2 = y.ToNumber()
- nan_string = str(NaN)
- if str(n1) == nan_string or str(n2) == nan_string:
+ if isnan(n1) or isnan(n2):
return False
if n1 == n2:
return True
@@ -573,10 +577,11 @@
++value (prefix) and value++ (postfix)
"""
def eval(self, ctx):
+ # XXX write down fast version
thing = self.expr.eval(ctx)
val = thing.GetValue()
x = val.ToNumber()
- resl = plus(ctx, W_Number(x), W_Number(1))
+ resl = plus(ctx, W_FloatNumber(x), W_IntNumber(1))
thing.PutValue(resl, ctx)
if self.postfix:
return val
@@ -589,10 +594,11 @@
same as increment --value and value --
"""
def eval(self, ctx):
+ # XXX write down hot path
thing = self.expr.eval(ctx)
val = thing.GetValue()
x = val.ToNumber()
- resl = sub(ctx, W_Number(x), W_Number(1))
+ resl = sub(ctx, W_FloatNumber(x), W_IntNumber(1))
thing.PutValue(resl, ctx)
if self.postfix:
return val
@@ -632,31 +638,61 @@
sleft = nleft.ToString(ctx)
sright = nright.ToString(ctx)
return W_String(sleft + sright)
+ # hot path
+ if isinstance(nleft, W_IntNumber) and isinstance(nright, W_IntNumber):
+ ileft = nleft.ToInt32()
+ iright = nright.ToInt32()
+ try:
+ return W_IntNumber(ovfcheck(ileft + iright))
+ except OverflowError:
+ return W_FloatNumber(float(ileft) + float(iright))
else:
fleft = nleft.ToNumber()
fright = nright.ToNumber()
- return W_Number(fleft + fright)
+ return W_FloatNumber(fleft + fright)
def mult(ctx, nleft, nright):
+ if isinstance(nleft, W_IntNumber) and isinstance(nright, W_IntNumber):
+ ileft = nleft.ToInt32()
+ iright = nright.ToInt32()
+ try:
+ return W_IntNumber(ovfcheck(ileft * iright))
+ except OverflowError:
+ return W_FloatNumber(float(ileft) * float(iright))
fleft = nleft.ToNumber()
fright = nright.ToNumber()
- return W_Number(fleft * fright)
+ return W_FloatNumber(fleft * fright)
def mod(ctx, nleft, nright): # XXX this one is really not following spec
ileft = nleft.ToInt32()
iright = nright.ToInt32()
- return W_Number(ileft % iright)
+ return W_IntNumber(ileft % iright)
def division(ctx, nleft, nright):
fleft = nleft.ToNumber()
fright = nright.ToNumber()
- return W_Number(fleft / fright)
+ if fright == 0:
+ if fleft < 0:
+ val = -INFINITY
+ elif fleft == 0:
+ val = NAN
+ else:
+ val = INFINITY
+ else:
+ val = fleft / fright
+ return W_FloatNumber(val)
def sub(ctx, nleft, nright):
+ if isinstance(nleft, W_IntNumber) and isinstance(nright, W_IntNumber):
+ ileft = nleft.ToInt32()
+ iright = nright.ToInt32()
+ try:
+ return W_IntNumber(ovfcheck(ileft - iright))
+ except OverflowError:
+ return W_FloatNumber(float(ileft) - float(iright))
fleft = nleft.ToNumber()
fright = nright.ToNumber()
- return W_Number(fleft - fright)
-
+ return W_FloatNumber(fleft - fright)
class Plus(BinaryNumberOp):
def mathop(self, ctx, n1, n2):
@@ -714,17 +750,25 @@
x = self.left.eval(ctx).GetValue()
args = self.right.eval(ctx).get_args()
return commonnew(ctx, x, args)
+
+class BaseNumber(Expression):
+ pass
+class IntNumber(BaseNumber):
+ def __init__(self, pos, num):
+ self.pos = pos
+ self.num = num
+ def eval(self, ctx):
+ return W_IntNumber(int(self.num))
-class Number(Expression):
+class FloatNumber(BaseNumber):
def __init__(self, pos, num):
self.pos = pos
- assert isinstance(num, float)
self.num = num
def eval(self, ctx):
- return W_Number(self.num)
+ return W_FloatNumber(float(self.num))
class String(Expression):
def __init__(self, pos, strval):
@@ -740,6 +784,7 @@
def string_unquote(self, string):
temp = []
stop = len(string)-1
+ # XXX proper error
assert stop >= 0
last = ""
@@ -784,7 +829,7 @@
def execute(self, ctx):
for varname in self.var_decl:
- ctx.variable.Put(varname, w_Undefined)
+ ctx.variable.Put(varname, w_Undefined, dd=True)
for funcname, funccode in self.func_decl.items():
ctx.variable.Put(funcname, funccode.eval(ctx))
node = self
@@ -880,9 +925,9 @@
def eval(self, ctx):
name = self.identifier.get_literal()
if self.expr is None:
- ctx.variable.Put(name, w_Undefined)
+ ctx.variable.Put(name, w_Undefined, dd=True)
else:
- ctx.variable.Put(name, self.expr.eval(ctx).GetValue())
+ ctx.variable.Put(name, self.expr.eval(ctx).GetValue(), dd=True)
return self.identifier.eval(ctx)
@@ -1050,9 +1095,17 @@
class UMinus(UnaryOp):
def eval(self, ctx):
- return W_Number(-self.expr.eval(ctx).GetValue().ToNumber())
+ res = self.expr.eval(ctx)
+ if isinstance(res, W_IntNumber):
+ return W_IntNumber(-res.intval)
+ elif isinstance(res, W_FloatNumber):
+ return W_FloatNumber(-res.floatval)
+ return W_FloatNumber(-self.expr.eval(ctx).GetValue().ToNumber())
class UPlus(UnaryOp):
def eval(self, ctx):
- return W_Number(+self.expr.eval(ctx).GetValue().ToNumber())
+ res = self.expr.eval(ctx)
+ if isinstance(res, W_BaseNumber):
+ return res
+ return W_FloatNumber(self.expr.eval(ctx).GetValue().ToNumber())
Modified: pypy/branch/jit-refactoring/pypy/lang/js/test/ecma/conftest.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/test/ecma/conftest.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test/ecma/conftest.py Tue Mar 11 10:42:56 2008
@@ -1,10 +1,11 @@
import py
from pypy.lang.js.interpreter import *
-from pypy.lang.js.jsobj import W_Array, JsBaseExcept
+from pypy.lang.js.jsobj import W_Array
from pypy.rlib.parsing.parsing import ParseError
from py.__.test.outcome import Failed, ExceptionFailure
import pypy.lang.js as js
from pypy.lang.js import interpreter
+from pypy.lang.js.execution import JsBaseExcept
interpreter.TEST = True
@@ -32,7 +33,7 @@
def init_interp(cls):
if hasattr(cls, 'interp'):
cls.testcases.PutValue(W_Array(), cls.interp.global_context)
- cls.tc.PutValue(W_Number(0), cls.interp.global_context)
+ cls.tc.PutValue(W_IntNumber(0), cls.interp.global_context)
cls.interp = Interpreter()
ctx = cls.interp.global_context
@@ -81,7 +82,7 @@
def run(self):
ctx = JSTestFile.interp.global_context
r3 = ctx.resolve_identifier('run_test').GetValue()
- w_test_number = W_Number(self.number)
+ w_test_number = W_IntNumber(self.number)
result = r3.Call(ctx=ctx, args=[w_test_number,]).GetValue().ToString()
if result != "passed":
raise Failed(msg=result)
Added: pypy/branch/jit-refactoring/pypy/lang/js/test/test_frames.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test/test_frames.py Tue Mar 11 10:42:56 2008
@@ -0,0 +1,4 @@
+
+class TestTraceback(object):
+ pass
+
Modified: pypy/branch/jit-refactoring/pypy/lang/js/test/test_interp.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/test/test_interp.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test/test_interp.py Tue Mar 11 10:42:56 2008
@@ -1,13 +1,13 @@
import py
from pypy.lang.js import interpreter
-from pypy.lang.js.operations import AEC, Number, Position, Plus
-from pypy.lang.js.jsobj import W_Number, W_Object, \
- ExecutionContext, W_Root, ThrowException, w_Null
+from pypy.lang.js.operations import AEC, IntNumber, FloatNumber, Position, Plus
+from pypy.lang.js.jsobj import W_Object, ExecutionContext, W_Root, w_Null
+from pypy.lang.js.execution import ThrowException
def test_simple():
- n1 = Number(Position(), 2.0)
- n2 = Number(Position(), 4.0)
+ n1 = FloatNumber(Position(), 2.0)
+ n2 = FloatNumber(Position(), 4.0)
p = Plus(Position(), n1, n2)
assert p.eval(ExecutionContext([W_Object(),])).GetValue().ToNumber() == 6.0
l = []
@@ -599,3 +599,6 @@
def test_new_without_args_really():
assertv("var x = new Boolean; x.toString();", 'false')
+def test_pypy_repr():
+ assertv("pypy_repr(3);", 'W_IntNumber')
+ assertv("pypy_repr(3.0);", 'W_FloatNumber')
Added: pypy/branch/jit-refactoring/pypy/lang/js/test/test_numbers.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test/test_numbers.py Tue Mar 11 10:42:56 2008
@@ -0,0 +1,10 @@
+
+from pypy.lang.js.test.test_interp import assertv
+
+def test_infinity_nan():
+ assertv('1/0', 'Infinity')
+ assertv('0/0', 'NaN')
+ assertv('-1/0', '-Infinity')
+
+def test_overflow_int_to_float():
+ assertv('1e200', '1e+200')
Modified: pypy/branch/jit-refactoring/pypy/lang/js/test/test_operations.py
==============================================================================
--- pypy/branch/jit-refactoring/pypy/lang/js/test/test_operations.py (original)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test/test_operations.py Tue Mar 11 10:42:56 2008
@@ -1,7 +1,7 @@
import py
from pypy.lang.js import interpreter
from pypy.lang.js.operations import *
-from pypy.lang.js.jsobj import W_Number, empty_context
+from pypy.lang.js.jsobj import empty_context
class MOCKNode(Node):
def __init__(self, pos, ret):
Added: pypy/branch/jit-refactoring/pypy/lang/js/test_scope.py
==============================================================================
--- (empty file)
+++ pypy/branch/jit-refactoring/pypy/lang/js/test_scope.py Tue Mar 11 10:42:56 2008
@@ -0,0 +1,8 @@
+
+from pypy.lang.js.test.test_interp import assertv
+
+def test_variable_deletion():
+ assertv("var x = 3; delete this.x;", False)
+ assertv("x = 3; delete this.x;", True)
+ assertv("var x = 3; delete this.x; x", 3)
+
More information about the Pypy-commit
mailing list