Skip to content

Commit 28af1bc

Browse files
author
hartsantler
committed
fixed bug in lua backend.
new optimization for '+' operator to bypass ternary/__add_op check `pythonjs.configure(direct_operator="+")`
1 parent ebfe4fa commit 28af1bc

3 files changed

Lines changed: 60 additions & 27 deletions

File tree

pythonjs/python_to_pythonjs.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class PythonToPythonJS(NodeVisitor):
167167
def __init__(self, source=None, module=None, module_path=None, dart=False, coffee=False, lua=False):
168168
super(PythonToPythonJS, self).__init__()
169169

170+
self._direct_operators = set() ## optimize "+" operator
170171
self._with_ll = False ## lowlevel
171172
self._with_lua = lua
172173
self._with_coffee = coffee
@@ -1124,19 +1125,23 @@ def visit_BinOp(self, node):
11241125
return 'Math.pow(%s,%s)' %(left, right)
11251126

11261127
elif op == '+' and not self._with_dart:
1127-
#return '__add_op(%s, %s)'%(left, right) ## this is very slow compared to using the ternary op with typeof check
1128-
## the ternary operator in javascript is fast, the add op needs to be fast for adding numbers, so here typeof is
1129-
## used to check if the first variable is a number, and if so add the numbers, otherwise fallback to using the
1130-
## __add_op function, the __add_op function checks if the first variable is an Array, and if so then concatenate;
1131-
## else __add_op will call the "__add__" method of the left operand, passing right as the first argument.
1132-
l = '__left%s' %self._addop_ids
1133-
self._addop_ids += 1
1134-
r = '__right%s' %self._addop_ids
1135-
writer.write('var(%s,%s)' %(l,r))
1136-
self._addop_ids += 1
1137-
writer.write('%s = %s' %(l,left))
1138-
writer.write('%s = %s' %(r,right))
1139-
return '__ternary_operator__( typeof(%s)=="number", %s + %s, __add_op(%s, %s))'%(l, l, r, l, r)
1128+
if '+' in self._direct_operators:
1129+
return '%s+%s'%(left, right)
1130+
elif self._with_lua:
1131+
return '__add_op(%s, %s)'%(left, right)
1132+
else:
1133+
## the ternary operator in javascript is fast, the add op needs to be fast for adding numbers, so here typeof is
1134+
## used to check if the first variable is a number, and if so add the numbers, otherwise fallback to using the
1135+
## __add_op function, the __add_op function checks if the first variable is an Array, and if so then concatenate;
1136+
## else __add_op will call the "__add__" method of the left operand, passing right as the first argument.
1137+
l = '__left%s' %self._addop_ids
1138+
self._addop_ids += 1
1139+
r = '__right%s' %self._addop_ids
1140+
writer.write('var(%s,%s)' %(l,r))
1141+
self._addop_ids += 1
1142+
writer.write('%s = %s' %(l,left))
1143+
writer.write('%s = %s' %(r,right))
1144+
return '__ternary_operator__( typeof(%s)=="number", %s + %s, __add_op(%s, %s))'%(l, l, r, l, r)
11401145

11411146
elif isinstance(node.left, Name):
11421147
typedef = self.get_typedef( node.left )
@@ -1765,6 +1770,13 @@ def visit_Call(self, node):
17651770
else:
17661771
raise SyntaxError
17671772

1773+
elif kw.arg == 'direct_operator':
1774+
assert kw.value.s in ['None', '+']
1775+
if kw.value.s == 'None':
1776+
self._direct_operators = set()
1777+
else:
1778+
self._direct_operators.add( kw.value.s )
1779+
17681780
else:
17691781
raise SyntaxError
17701782

regtests/bench/add.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
from time import clock
66

7+
78
def main():
9+
if PYTHON=='PYTHONJS': ## about 25% faster with normal and javascript backends
10+
pythonjs.configure( direct_operator='+' )
11+
pass
12+
813
start = clock()
914
a = 0
1015
for i in range(1000000):

regtests/run.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def runnable(command):
4949
dart2js_runnable = runnable( dart2js + ' -h' )
5050
coffee_runnable = runnable( "coffee -v" ) and '--all-backends' in sys.argv
5151
lua_runnable = runnable( "lua -v" ) and '--all-backends' in sys.argv
52-
luajit_runnable = runnable( "luajit -v" ) and '--all-backends' in sys.argv
52+
luajit_runnable = runnable( "luajit -v" )
5353

5454
lua2js = os.path.abspath( '../external/lua.js/lua2js' )
5555
luajs_runnable = os.path.isfile( lua2js ) and '--all-backends' in sys.argv
@@ -98,6 +98,9 @@ def run_command(command, returns_stdout_stderr=False):
9898
sys.exit()
9999
if returns_stdout_stderr:
100100
return stdout, stderr
101+
102+
#########################
103+
101104
if stdout:
102105
if show_details:
103106
print(stdout)
@@ -172,7 +175,7 @@ def TestWarning(file, line, result, test):
172175
print(file + ":" + str(line) + " Warning fail " + test)
173176
"""
174177

175-
def patch_python(filename, dart=False, python='PYTHONJS'):
178+
def patch_python(filename, dart=False, python='PYTHONJS', backend=None):
176179
"""Rewrite the Python code"""
177180
code = patch_assert(filename)
178181

@@ -191,10 +194,17 @@ def patch_python(filename, dart=False, python='PYTHONJS'):
191194
# else:
192195
# out.append( line )
193196
# code = '\n'.join( out )
194-
if dart:
195-
return '\n'.join( [_patch_header, 'PYTHON="%s"'%python, code] )
196-
else:
197-
return '\n'.join( [_patch_header, 'PYTHON="%s"'%python, code, 'main()'] )
197+
a = [
198+
_patch_header,
199+
'PYTHON="%s"'%python,
200+
'BACKEND="%s"'%backend,
201+
code
202+
]
203+
204+
if not dart:
205+
a.append( 'main()' )
206+
207+
return '\n'.join( a )
198208

199209
def run_python_test_on(filename):
200210
"""Python2"""
@@ -213,27 +223,33 @@ def run_pypy_test_on(filename):
213223

214224

215225
def translate_js(filename, javascript=False, dart=False, coffee=False, lua=False, luajs=False):
226+
global tmpname
227+
tmpname = os.path.join(
228+
tempfile.gettempdir(),
229+
'test-%s-js=%s-dart=%s-lua=%s' %(filename.split('/')[-1], javascript, dart, lua)
230+
)
231+
216232
output_name = "%s.py" % tmpname
217233
if javascript:
218-
content = 'pythonjs.configure(javascript=True)\n' + patch_python(filename)
234+
content = 'pythonjs.configure(javascript=True)\n' + patch_python(filename, backend='JAVASCRIPT')
219235
elif dart:
220236
source = [
221237
'pythonjs.configure(dart=True)',
222238
open('../pythonjs/runtime/dart_builtins.py', 'rb').read().decode('utf-8'),
223-
patch_python(filename, dart=True)
239+
patch_python(filename, dart=True, backend='DART')
224240
]
225241
content = '\n'.join( source )
226242
elif coffee:
227243
source = [
228244
'pythonjs.configure(coffee=True)',
229-
patch_python(filename)
245+
patch_python(filename, backend='COFFEE')
230246
]
231247
content = '\n'.join( source )
232248
elif lua or luajs:
233249
source = [
234250
'pythonjs.configure(lua=True)',
235251
read('../pythonjs/runtime/lua_builtins.py'),
236-
patch_python(filename)
252+
patch_python(filename, backend='LUA')
237253
]
238254
content = '\n'.join( source )
239255

@@ -363,11 +379,11 @@ def run_js_rhino(content):
363379
return run_command("rhino -O -1 %s.js" % tmpname)
364380

365381
def run_pythonjs_test_on_node(dummy_filename):
366-
"""PythonJS (normal mode)"""
382+
"""PythonJS (normal)"""
367383
return run_if_no_error(run_js_node)
368384

369385
def run_pythonjsjs_test_on_node(filename):
370-
"""PythonJS (fast mode)"""
386+
"""PythonJS (fast backend)"""
371387
return run_pythonjs_test_on_node(filename)
372388

373389
def run_js_node(content):
@@ -380,7 +396,7 @@ def run_js_node(content):
380396
return run_command("node %s.js" % tmpname)
381397

382398
def run_pythonjs_dart_test_on_node(dummy_filename):
383-
"""PythonJS (dart2js)"""
399+
"""PythonJS (Dart backend)"""
384400
return run_if_no_error(run_dart2js_node)
385401

386402
def run_dart2js_node(content):
@@ -410,7 +426,7 @@ def run_lua_lua(content):
410426

411427

412428
def run_pythonjs_lua_test_on_luajit(dummy_filename):
413-
"""PythonJS (Lua) on LuaJIT"""
429+
"""PythonJS (LuaJIT backend)"""
414430
return run_if_no_error(run_lua_luajit)
415431

416432
def run_lua_luajit(content):

0 commit comments

Comments
 (0)