Author: Stephan <[email protected]>
Branch:
Changeset: r138:6fcde575af3d
Date: 2011-10-25 13:00 +0200
http://bitbucket.org/pypy/lang-js/changeset/6fcde575af3d/
Log: replaced W_PrimitiveObject.propdict with object map
diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -302,7 +302,7 @@
def Call(self, ctx, args=[], this=None):
if len(args) >= 1:
propname = args[0].ToString(ctx)
- if propname in this.propdict:
+ if propname in self._get_property_keys():
return newbool(True)
return newbool(False)
@@ -321,7 +321,7 @@
def Call(self, ctx, args=[], this=None):
if len(args) >= 1:
propname = args[0].ToString(ctx)
- if propname in this.propdict and not this.propdict[propname].flags
& DONT_ENUM:
+ if self._has_property(propname) and not
self._get_property_flags(propname) & DONT_ENUM:
return newbool(True)
return newbool(False)
@@ -728,8 +728,7 @@
w_ObjPrototype = W_Object(Prototype=None, Class='Object')
- w_Function = W_Function(ctx, Class='Function',
- Prototype=w_ObjPrototype)
+ w_Function = W_Function(ctx, Class='Function',
Prototype=w_ObjPrototype)
w_FncPrototype = W_Function(ctx, Class='Function',
Prototype=w_ObjPrototype)#W_Object(Prototype=None, Class='Function')
w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon)
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -15,6 +15,12 @@
READ_ONLY = RO = 4 # ReadOnly
INTERNAL = IT = 8 # Internal
+from js.object_map import MapRoot
+ROOT_MAP = MapRoot()
+
+def _get_root_map():
+ return ROOT_MAP
+
class SeePage(NotImplementedError):
pass
@@ -147,8 +153,9 @@
class W_PrimitiveObject(W_Root):
def __init__(self, ctx=None, Prototype=None, Class='Object',
Value=w_Undefined, callfunc=None):
- self._propdict = {}
self.Prototype = Prototype
+ self.property_map = _get_root_map()
+ self.property_values = []
if Prototype is None:
Prototype = w_Undefined
self._set_property('prototype', Prototype, DONT_ENUM | DONT_DELETE)
@@ -161,44 +168,56 @@
self.Value = Value
def _set_property(self, name, value, flags):
- p = self._propdict.get(name, None)
- if p is None:
- p = Property(name, value, flags)
- self._propdict[name] = p
- else:
- p.value = value
- p.falgs = flags
+ if self.property_map.lookup(name) == self.property_map.NOT_FOUND:
+ self.property_map = self.property_map.add(name, flags)
+ self._set_property_value(name, value)
+ self._set_property_flags(name, flags)
def _set_property_value(self, name, value):
- self._get_property(name).value = value
+ idx = self.property_map.lookup(name)
+ l = len(self.property_values)
+
+ if l <= idx:
+ self.property_values = self.property_values + ([None] * (idx - l +
1))
+
+ self.property_values[idx] = value
def _set_property_flags(self, name, flags):
- self._get_property(name).flags = flags
+ self.property_map = self.property_map.set_flags(name, flags)
def _get_property_value(self, name):
- p = self._get_property(name)
- if p is None:
+ idx = self.property_map.lookup(name)
+ if idx == self.property_map.NOT_FOUND:
raise KeyError
- return p.value
-
+ return self.property_values[idx]
def _get_property_flags(self, name):
- p = self._get_property(name)
- if p is None:
+ flag = self.property_map.lookup_flag(name)
+ if flag == self.property_map.NOT_FOUND:
raise KeyError
- return p.flags
-
- def _get_property(self, name):
- return self._propdict.get(name, None)
+ return flag
def _has_property(self, name):
- return name in self._propdict
+ return self.property_map.lookup(name) != self.property_map.NOT_FOUND
def _delete_property(self, name):
- del self._propdict[name]
+ idx = self.property_map.lookup(name)
+ old_map = self.property_map
+ new_map = self.property_map.delete(name)
+ new_keys = new_map.keys()
+ new_values = [None] * len(new_keys)
+ old_values = self.property_values
+
+ for key in new_keys:
+ old_index = old_map.lookup(key)
+ new_index = new_map.lookup(key)
+ new_values[new_index] = old_values[old_index]
+
+ self.property_values = new_values
+ self.property_map = new_map
def _get_property_keys(self):
- return self._propdict.keys()
+ return self.property_map.keys()
#@jit.unroll_safe
def Call(self, ctx, args=[], this=None):
@@ -331,18 +350,15 @@
return W_String(this.ToString(ctx))
class W_Object(W_PrimitiveObject):
- def __init__(self, ctx=None, Prototype=None, Class='Object',
- Value=w_Undefined, callfunc=None):
- W_PrimitiveObject.__init__(self, ctx, Prototype,
- Class, Value, callfunc)
+ def __init__(self, ctx=None, Prototype=None, Class='Object',
Value=w_Undefined, callfunc=None):
+ W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value,
callfunc)
def ToNumber(self, ctx):
return self.Get(ctx, 'valueOf').Call(ctx, args=[],
this=self).ToNumber(ctx)
class W_NewBuiltin(W_PrimitiveObject):
length = -1
- def __init__(self, ctx, Prototype=None, Class='function',
- Value=w_Undefined, callfunc=None):
+ def __init__(self, ctx, Prototype=None, Class='function',
Value=w_Undefined, callfunc=None):
if Prototype is None:
proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype')
Prototype = proto
@@ -402,7 +418,7 @@
self._delete_property('prototype')
def __repr__(self):
- return str(self.propdict)
+ return str(self.property_map)
class W_Array(W_ListObject):
def __init__(self, ctx=None, Prototype=None, Class='Array',
Value=w_Undefined, callfunc=None):
@@ -660,8 +676,7 @@
def create_object(ctx, prototypename, callfunc=None, Value=w_Undefined):
proto = ctx.get_global().Get(ctx, prototypename).Get(ctx, 'prototype')
- obj = W_Object(ctx, callfunc = callfunc,Prototype=proto,
- Class = proto.Class, Value = Value)
+ obj = W_Object(ctx, callfunc = callfunc,Prototype=proto, Class =
proto.Class, Value = Value)
obj.Put(ctx, '__proto__', proto, DONT_ENUM | DONT_DELETE | READ_ONLY)
return obj
diff --git a/js/object_map.py b/js/object_map.py
new file mode 100644
--- /dev/null
+++ b/js/object_map.py
@@ -0,0 +1,99 @@
+from pypy.rlib import jit
+
+class Map(object):
+ NOT_FOUND = -1
+ _immutable_fields_ = ['index', 'back', 'name', 'flags']
+ def __init__(self):
+ self.index = self.NOT_FOUND
+ self.forward_pointers = {}
+ self.back = None
+ self.name = None
+ self.flags = 0
+
+ def __repr__(self):
+ return "%s : %s:%d -> %s" % (object.__repr__(self), self.name,
self.flags, repr(self.back) )
+
+ def lookup(self, name):
+ jit.promote(self)
+ node = self._find_node_with_name(name)
+ if node is not None:
+ return node.index
+ return self.NOT_FOUND
+
+ def lookup_flag(self, name):
+ jit.promote(self)
+ node = self._find_node_with_name(name)
+ if node is not None:
+ return node.flags
+ return self.NOT_FOUND
+
+ def _find_node_with_name(self, name):
+ if self.name == name:
+ return self
+ if self.back is not None:
+ return self.back._find_node_with_name(name)
+
+ def _find_node_with_name_and_flags(self, name, flags):
+ if self.name == name and self.flags == flags:
+ return self
+ node = None
+ if self.back is not None:
+ node = self.back._find_node_with_name_and_flags(name, flags)
+ if node is None:
+ return self.forward_pointers.get((name, flags), None)
+
+ def _key(self):
+ return (self.name, self.flags)
+
+ @jit.elidable
+ def add(self, name, flags=0):
+ assert self.lookup(name) == self.NOT_FOUND
+ node = self.forward_pointers.get((name, flags), None)
+ if node is None:
+ node = MapNode(self, name, flags)
+ self.forward_pointers[node._key()] = node
+ return node
+
+ def keys(self):
+ if self.name is None:
+ return []
+
+ k = [self.name]
+ if self.back is not None:
+ return self.back.keys() + k
+
+ return k
+
+ def set_flags(self, name, flags):
+ return self
+
+ def delete(self, key):
+ return self
+
+class MapRoot(Map):
+ pass
+
+class MapNode(Map):
+ def __init__(self, back, name, flags = 0):
+ Map.__init__(self)
+ self.back = back
+ self.name = name
+ self.index = back.index + 1
+ self.flags = flags
+
+ def delete(self, name):
+ if self.name == name:
+ return self.back
+ else:
+ n = self.back.delete(name)
+ return n.add(self.name, self.flags)
+
+ def set_flags(self, name, flags):
+ if self.name == name:
+ if self.flags == flags:
+ return self
+ else:
+ return self.back.add(name, flags)
+ else:
+ n = self.back.set_flags(name, flags)
+ return n.add(self.name, self.flags)
diff --git a/js/test/test_object_map.py b/js/test/test_object_map.py
new file mode 100644
--- /dev/null
+++ b/js/test/test_object_map.py
@@ -0,0 +1,175 @@
+import py
+
+from js.object_map import Map, MapRoot, MapNode
+
+class TestMap(object):
+ def setup_class(cls):
+ pass
+
+ def setup_method(cls, func):
+ pass
+
+ def test_root(self):
+ m = MapRoot()
+ assert m.index == Map.NOT_FOUND
+
+ def test_lookup_empty_root(self):
+ m = MapRoot()
+ assert m.lookup('foo') == Map.NOT_FOUND
+
+ def test_lookup(self):
+ a = MapRoot()
+ b = MapNode(a, 'foo')
+ c = MapNode(b, 'bar')
+ d = MapNode(b, 'baz')
+ e = MapNode(a, 'bar')
+
+ assert a.lookup('foo') == Map.NOT_FOUND
+ assert a.lookup('bar') == Map.NOT_FOUND
+ assert a.lookup('baz') == Map.NOT_FOUND
+ assert b.lookup('foo') == 0
+ assert b.lookup('bar') == Map.NOT_FOUND
+ assert b.lookup('baz') == Map.NOT_FOUND
+ assert c.lookup('foo') == 0
+ assert c.lookup('bar') == 1
+ assert c.lookup('baz') == Map.NOT_FOUND
+ assert d.lookup('foo') == 0
+ assert d.lookup('bar') == Map.NOT_FOUND
+ assert d.lookup('baz') == 1
+ assert e.lookup('bar') == 0
+
+ def test_add_node(self):
+ a = MapRoot()
+ b = a.add('foo')
+ assert b._key() in a.forward_pointers
+ assert a.forward_pointers[b._key()] == b
+ assert b.index == 0
+ assert b.back == a
+
+ c = b.add('bar')
+ assert c.lookup('bar') == 1
+
+ d = b.add('baz')
+ assert d.lookup('baz') == 1
+ assert c.lookup('baz') == Map.NOT_FOUND
+
+ py.test.raises(AssertionError, c.add, 'bar')
+
+ def test_add_duplicate(self):
+ r = MapRoot()
+ a = r.add('foo')
+ b = r.add('foo')
+ assert a == b
+
+ a = a.add('bar')
+ b = b.add('bar')
+
+ assert a == b
+
+ def test_keys(self):
+ m = MapRoot()
+ a = m.add('foo')
+ a = a.add('bar')
+ a = a.add('baz')
+
+ b = m.add('baz')
+ b = b.add('bar')
+
+ assert a.keys() == ['foo', 'bar', 'baz']
+ assert b.keys() == ['baz', 'bar']
+
+ def test_delete(self):
+ m = MapRoot()
+ m = m.add('foo')
+ m = m.add('bar')
+ m = m.add('baz')
+
+ b = m.delete('foo')
+ c = m.delete('bar')
+
+ assert b.lookup('foo') == Map.NOT_FOUND
+ assert b.lookup('bar') == 0
+ assert b.lookup('baz') == 1
+ assert b.keys() == ['bar', 'baz']
+
+ assert m.lookup('foo') == 0
+ assert m.lookup('bar') == 1
+ assert m.lookup('baz') == 2
+ assert m.keys() == ['foo', 'bar', 'baz']
+
+ assert c.lookup('foo') == 0
+ assert c.lookup('bar') == Map.NOT_FOUND
+ assert c.lookup('baz') == 1
+ assert c.keys() == ['foo', 'baz']
+
+ def test_delete_add(self):
+ m = MapRoot()
+ m = m.add('foo')
+ m = m.add('bar')
+ m = m.add('baz')
+
+ b = m.delete('foo')
+ b = b.add('foo')
+
+ assert b.lookup('foo') == 2
+ assert b.lookup('bar') == 0
+ assert b.lookup('baz') == 1
+ assert b.keys() == ['bar', 'baz', 'foo']
+
+ def test_delete_duplicate(self):
+ r = MapRoot()
+ a = r.add('bar')
+ a = a.add('baz')
+
+ b = r.add('foo')
+ b = b.add('bar')
+ b = b.add('baz')
+ b = b.delete('foo')
+
+ assert b.lookup('foo') == Map.NOT_FOUND
+ assert b.lookup('bar') == 0
+ assert b.lookup('baz') == 1
+
+ assert a.lookup('bar') == 0
+ assert a.lookup('baz') == 1
+
+ assert a == b
+
+ def test_add_with_flags(self):
+ r = MapRoot()
+ a = r.add('foo', 23)
+ a = a.add('bar')
+ b = r.add('foo', 42)
+ b = b.add('bar')
+
+ assert a.lookup('foo') == 0
+ assert a.lookup('bar') == 1
+
+ assert b.lookup('foo') == 0
+ assert b.lookup('bar') == 1
+
+ assert a.lookup_flag('foo') == 23
+ assert a.lookup_flag('bar') == 0
+ assert b.lookup_flag('foo') == 42
+ assert b.lookup_flag('bar') == 0
+
+ def test_set_flags(self):
+ r = MapRoot()
+ a = r.add('foo', 23)
+ a = a.add('bar')
+ a = a.add('baz')
+ b = r.add('foo', 42)
+ b = b.add('bar')
+ b = b.add('baz')
+
+
+ c = a.set_flags('bar', 42)
+ d = b.set_flags('bar', 23)
+
+ assert a.lookup_flag('bar') == 0
+ assert b.lookup_flag('bar') == 0
+ assert c.lookup_flag('bar') == 42
+ assert d.lookup_flag('bar') == 23
+
+ assert a.back.back == c.back.back
+ assert b.back.back == d.back.back
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit