[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