[pypy-svn] r48203 - in pypy/dist/pypy/lang/smalltalk: . test
arigo at codespeak.net
arigo at codespeak.net
Tue Oct 30 17:46:10 CET 2007
Author: arigo
Date: Tue Oct 30 17:46:08 2007
New Revision: 48203
Modified:
pypy/dist/pypy/lang/smalltalk/interpreter.py
pypy/dist/pypy/lang/smalltalk/test/test_interpreter.py
Log:
A conservative fix of the bytecodePrimXxx(): always use
_sendSelfSelector() unless it is safe to directly invoke the primitive
because the latter checks the class of the receiver. This is mostly
what Squeak does too.
Also add a call to the FLOAT_XYZ primitive if the XYZ primitive failed
(i.e. the arguments were not integers).
Modified: pypy/dist/pypy/lang/smalltalk/interpreter.py
==============================================================================
--- pypy/dist/pypy/lang/smalltalk/interpreter.py (original)
+++ pypy/dist/pypy/lang/smalltalk/interpreter.py Tue Oct 30 17:46:08 2007
@@ -334,48 +334,80 @@
def longJumpIfFalse(self, interp):
self.jumpConditional(interp.FALSE,self.longJumpPosition())
- def callPrimitive(self, primitive, selector,
- argcount, interp):
- # XXX XXX REMEMBER TO SWITCH COMMENT AND ACTUAL CODE BEFORE
- # TESTING ON AN IMAGE, AND TO LEAVE AS IS FOR TESTCODE (and
- # vice versa)
+ def callPrimitive(self, primitive, selector, argcount, interp):
+ # WARNING: this is used for bytecodes for which it is safe to
+ # directly call the primitive. In general, it is not safe: for
+ # example, depending on the type of the receiver, bytecodePrimAt
+ # may invoke primitives.AT, primitives.STRING_AT, or anything
+ # else that the user put in a class in an 'at:' method.
+ # The rule of thumb is that primitives with only int and float
+ # in their unwrap_spec are safe.
try:
# note that argcount does not include self
- w_result = primitives.prim_table[primitive](interp, argcount)
+ primitives.prim_table[primitive](interp, argcount)
# the primitive pushes the result (if any) onto the stack itself
except primitives.PrimitiveFailedError:
self._sendSelfSelector(selector, argcount, interp)
- #self._sendSelfSelector(selector, argcount, interp)
+
+ def callPrimitive2(self, primitive1, primitive2,
+ selector, argcount, interp):
+ # same as callPrimitive(), but tries two primitives before falling
+ # back to the general case.
+ try:
+ primitives.prim_table[primitive1](interp, argcount)
+ # the primitive pushes the result (if any) onto the stack itself
+ except primitives.PrimitiveFailedError:
+ self.callPrimitive(primitive2, selector, argcount, interp)
def bytecodePrimAdd(self, interp):
- self.callPrimitive(primitives.ADD, "+", 1, interp)
+ self.callPrimitive2(primitives.ADD,
+ primitives.FLOAT_ADD,
+ "+", 1, interp)
def bytecodePrimSubtract(self, interp):
- self.callPrimitive(primitives.SUBTRACT, "-", 1, interp)
+ self.callPrimitive2(primitives.SUBTRACT,
+ primitives.FLOAT_SUBTRACT,
+ "-", 1, interp)
def bytecodePrimLessThan(self, interp):
- self.callPrimitive(primitives.LESSTHAN, "<", 1, interp)
+ self.callPrimitive2(primitives.LESSTHAN,
+ primitives.FLOAT_LESSTHAN,
+ "<", 1, interp)
def bytecodePrimGreaterThan(self, interp):
- self.callPrimitive(primitives.GREATERTHAN, ">", 1, interp)
+ self.callPrimitive2(primitives.GREATERTHAN,
+ primitives.FLOAT_GREATERTHAN,
+ ">", 1, interp)
def bytecodePrimLessOrEqual(self, interp):
- self.callPrimitive(primitives.LESSOREQUAL, "<=", 1, interp)
+ self.callPrimitive2(primitives.LESSOREQUAL,
+ primitives.FLOAT_LESSOREQUAL,
+ "<=", 1, interp)
def bytecodePrimGreaterOrEqual(self, interp):
- self.callPrimitive(primitives.GREATEROREQUAL, ">=", 1, interp)
+ self.callPrimitive2(primitives.GREATEROREQUAL,
+ primitives.FLOAT_GREATEROREQUAL,
+ ">=", 1, interp)
def bytecodePrimEqual(self, interp):
- self.callPrimitive(primitives.EQUAL, "=", 1, interp)
+ self.callPrimitive2(primitives.EQUAL,
+ primitives.FLOAT_EQUAL,
+ "=", 1, interp)
def bytecodePrimNotEqual(self, interp):
- self.callPrimitive(primitives.NOTEQUAL, "~=", 1, interp)
+ self.callPrimitive2(primitives.NOTEQUAL,
+ primitives.FLOAT_NOTEQUAL,
+ "~=", 1, interp)
def bytecodePrimMultiply(self, interp):
- self.callPrimitive(primitives.MULTIPLY, "*", 1, interp)
+ self.callPrimitive2(primitives.MULTIPLY,
+ primitives.FLOAT_MULTIPLY,
+ "*", 1, interp)
def bytecodePrimDivide(self, interp):
- self.callPrimitive(primitives.DIVIDE, "/", 1, interp)
+ self.callPrimitive2(primitives.DIVIDE,
+ primitives.FLOAT_DIVIDE,
+ "/", 1, interp)
def bytecodePrimMod(self, interp):
self.callPrimitive(primitives.MOD, "\\\\", 1, interp)
@@ -399,42 +431,50 @@
# n.b.: depending on the type of the receiver, this may invoke
# primitives.AT, primitives.STRING_AT, or something else for all
# I know.
- #self.callPrimitive(primitives.AT, "at:", 1, interp)
self._sendSelfSelector("at:", 1, interp)
def bytecodePrimAtPut(self, interp):
# n.b. as above
- #self.callPrimitive(primitives.AT_PUT, "at:put:", 2, interp)
self._sendSelfSelector("at:put:", 2, interp)
def bytecodePrimSize(self, interp):
- self.callPrimitive(primitives.SIZE, "size", 0, interp)
+ self._sendSelfSelector("size", 0, interp)
def bytecodePrimNext(self, interp):
- self.callPrimitive(primitives.NEXT, "next", 0, interp)
+ self._sendSelfSelector("next", 0, interp)
def bytecodePrimNextPut(self, interp):
- self.callPrimitive(primitives.NEXT_PUT, "nextPut:", 1, interp)
+ self._sendSelfSelector("nextPut:", 1, interp)
def bytecodePrimAtEnd(self, interp):
- self.callPrimitive(primitives.AT_END, "atEnd", 0, interp)
+ self._sendSelfSelector("atEnd", 0, interp)
def bytecodePrimEquivalent(self, interp):
- self.callPrimitive(primitives.EQUIVALENT, "==", 1, interp)
+ # short-circuit: classes cannot override the '==' method,
+ # which cannot fail
+ primitives.prim_table[primitives.EQUIVALENT](interp, 1)
def bytecodePrimClass(self, interp):
- self.callPrimitive(
- primitives.CLASS, "class", 0, interp)
+ # short-circuit: classes cannot override the 'class' method,
+ # which cannot fail
+ primitives.prim_table[primitives.CLASS](interp, 0)
def bytecodePrimBlockCopy(self, interp):
- self.callPrimitive(
- primitives.PRIMITIVE_BLOCK_COPY, "blockCopy:", 1, interp)
+ # the primitive checks the class of the receiver
+ self.callPrimitive(primitives.PRIMITIVE_BLOCK_COPY,
+ "blockCopy:", 1, interp)
def bytecodePrimValue(self, interp):
+ # the primitive checks the class of the receiver
self.callPrimitive(
primitives.PRIMITIVE_VALUE, "value", 0, interp)
def bytecodePrimValueWithArg(self, interp):
+ # the primitive checks the class of the receiver
+ # Note that the PRIMITIVE_VALUE_WITH_ARGS takes an array of
+ # arguments but this bytecode is about the one-argument case.
+ # The PRIMITIVE_VALUE is general enough to take any number of
+ # arguments from the stack, so it's the one we need to use here.
self.callPrimitive(
primitives.PRIMITIVE_VALUE, "value:", 1, interp)
@@ -442,10 +482,10 @@
self._sendSelfSelector("do:", 1, interp)
def bytecodePrimNew(self, interp):
- self.callPrimitive(primitives.NEW, "new", 0, interp)
+ self._sendSelfSelector("new", 0, interp)
def bytecodePrimNewWithArg(self, interp):
- self.callPrimitive(primitives.NEW_WITH_ARG, "new:", 1, interp)
+ self._sendSelfSelector("new:", 1, interp)
def bytecodePrimPointX(self, interp):
self._sendSelfSelector("x", 0, interp)
Modified: pypy/dist/pypy/lang/smalltalk/test/test_interpreter.py
==============================================================================
--- pypy/dist/pypy/lang/smalltalk/test/test_interpreter.py (original)
+++ pypy/dist/pypy/lang/smalltalk/test/test_interpreter.py Tue Oct 30 17:46:08 2007
@@ -330,21 +330,29 @@
assert interp.w_active_context.stack == []
def test_bytecodePrimNew():
- w_fakeclass = mockclass(1, name='fakeclass', varsized=False)
+ w_fakeclassclass = mockclass(10, name='fakeclassclass')
+ w_fakeclass = mockclass(1, name='fakeclass', varsized=False,
+ w_metaclass=w_fakeclassclass)
interp = new_interpreter(bytecodePrimNew)
interp.w_active_context.push(w_fakeclass)
- interp.step()
+ run_with_faked_methods(
+ [[w_fakeclassclass, primitives.NEW, 0, "new"]],
+ interp.step)
w_fakeinst = interp.w_active_context.pop()
assert interp.w_active_context.stack == []
assert w_fakeinst.getclass() == w_fakeclass
assert w_fakeinst.size() == 1
def test_bytecodePrimNewWithArg():
- w_fakeclass = mockclass(1, name='fakeclass', varsized=True)
+ w_fakeclassclass = mockclass(10, name='fakeclassclass')
+ w_fakeclass = mockclass(1, name='fakeclass', varsized=True,
+ w_metaclass=w_fakeclassclass)
interp = new_interpreter(bytecodePrimNewWithArg)
interp.w_active_context.push(w_fakeclass)
interp.w_active_context.push(interpreter.Interpreter.TWO)
- interp.step()
+ run_with_faked_methods(
+ [[w_fakeclassclass, primitives.NEW_WITH_ARG, 1, "new:"]],
+ interp.step)
w_fakeinst = interp.w_active_context.pop()
assert interp.w_active_context.stack == []
assert w_fakeinst.getclass() == w_fakeclass
@@ -355,7 +363,9 @@
w_fakeinst = w_fakeclass.as_class_get_shadow().new(5)
interp = new_interpreter(bytecodePrimSize)
interp.w_active_context.push(w_fakeinst)
- interp.step()
+ run_with_faked_methods(
+ [[w_fakeclass, primitives.SIZE, 0, "size"]],
+ interp.step)
assert interp.w_active_context.pop().value == 5
assert interp.w_active_context.stack == []
More information about the Pypy-commit
mailing list