issue #98 merge changes from master

pull/167/head
Dibyendu Majumdar 7 years ago
commit d477e76155

@ -28,6 +28,6 @@ script:
- if [ "$CXX" = "g++" ]; then export CXX="ccache g++-5" CC="ccache gcc-5"; fi
- if [ "$CXX" = "clang++" ]; then export CXX="ccache clang++-3.7" CC="ccache clang-3.7"; fi
- mkdir $TRAVIS_BUILD_DIR/build
- cd $TRAVIS_BUILD_DIR/build && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=/tmp/LLVM37/share/llvm/cmake -G "Unix Makefiles" -DLLVM_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/build && $TRAVIS_BUILD_DIR/cmake-3.4.0-Linux-x86_64/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=/tmp/LLVM37/share/llvm/cmake -G "Unix Makefiles" -DLLVM_JIT=ON ..
- cd $TRAVIS_BUILD_DIR/build && make
- cd $TRAVIS_BUILD_DIR/lua-tests && sh ./run_tests.sh $TRAVIS_BUILD_DIR/build/ravi
- cd $TRAVIS_BUILD_DIR/lua-tests && sh ./run_travis_tests.sh $TRAVIS_BUILD_DIR/build/ravi

@ -87,10 +87,12 @@ if (CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE)
endif ()
# -fsanitize=bounds -fsanitize=alignment -fsanitize=object-size
set(SANITIZER_FLAGS "-fsanitize=address")
set(CMAKE_C_FLAGS "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -std=c99 -O0 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O2 -fomit-frame-pointer -Wall -Wextra -Winline -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -std=c99 -O1 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O2 -fomit-frame-pointer -Wall -Wno-sign-compare -Winline -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_DEBUG "${SANITIZER_FLAGS} -fno-omit-frame-pointer -fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${SANITIZER_FLAGS} -fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 ${CXX_OPTIONS}")
# In case we are using gcc 5.1 set ABI version
@ -98,11 +100,11 @@ if (CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE)
endif ()
if (APPLE)
set(CMAKE_C_FLAGS "-std=c99 -O1 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS "-std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_DEBUG "-std=c99 -O0 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELEASE "-std=c99 -O3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-std=c99 -O1 -g3 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS "-O1 -g3 -Wall -fno-rtti -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS "-O3 -Wall -fno-rtti -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELEASE "-fno-rtti -O3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_DEBUG "-fno-rtti -O0 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-fno-rtti -O1 -g3 -Wall -Wno-sign-compare -std=c++11 -fno-exceptions -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX")
@ -138,7 +140,7 @@ endif()
set(LUA_CORE_SRCS src/lapi.c src/lcode.c src/lctype.c src/ldebug.c src/ldo.c src/ldump.c
src/lfunc.c src/lgc.c src/llex.c src/lmem.c src/lobject.c src/lopcodes.c
src/lparser.c src/lstate.c src/lstring.c src/ltable.c src/ltm.c src/lundump.c
src/lvm.c src/lzio.c src/ravijit.cpp src/ltests.c src/ravi_ast.c)
src/lvm.c src/lzio.c src/ravijit.cpp src/ltests.c src/ravi_profile.c src/ravi_ast.c)
# define the lua lib source files
set(LUA_LIB_SRCS src/lauxlib.c src/lbaselib.c src/lbitlib.c src/lcorolib.c src/ldblib.c src/liolib.c
src/lmathlib.c src/loslib.c src/ltablib.c src/lstrlib.c src/loadlib.c src/linit.c src/lutf8lib.c)

@ -1,3 +1,4 @@
=========================
Ravi Programming Language
=========================
@ -9,38 +10,43 @@ There are other attempts to add static typing to Lua - e.g. `Typed Lua <https://
My motivation is somewhat different - I want to enhance the VM to support more efficient operations when types are known. Type information can be exploited by JIT compilation technology to improve performance. At the same time, I want to keep the language safe and therefore usable by non-expert programmers.
Goals
-----
* Optional static typing for Lua
Of course there is also the fantastic `LuaJIT <http://luajit.org>`_ implementation. Ravi has a different goal compared to
LuaJIT. Ravi prioritizes ease of maintenance and support, language safety, and compatibility with Lua 5.3, over maximum performance. For more detailed comparison please refer to the documentation links below.
.. contents:: Table of Contents
:depth: 1
:backlinks: top
Features
========
* Optional static typing
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available
* LLVM bindings exposed in Lua
Documentation
--------------
=============
See `Ravi Documentation <http://the-ravi-programming-language.readthedocs.org/en/latest/index.html>`_.
As more stuff is built I will keep updating the documentation so please revisit for latest information.
Also see the slides I presented at the `Lua 2015 Workshop <http://www.lua.org/wshop15.html>`_.
JIT Implementation
++++++++++++++++++
==================
The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implemented in LLVM are described in `JIT Status <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-status.html>`_ page.
Ravi also provides an `LLVM binding <http://the-ravi-programming-language.readthedocs.org/en/latest/llvm-bindings.html>`_; this is still work in progress so please check documentation for the latest status.
As of July 2015 the `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation is also functional but some byte codes are not yet compiled, and featurewise this implementation is somewhat lagging behind the LLVM based implementation.
Performance Benchmarks
++++++++++++++++++++++
For performance benchmarks please visit the `Ravi Performance Benchmarks <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-benchmarks.html>`_ page.
There is also a `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation but this implementation is lagging behind the LLVM based implementation. Further development of this is currently not planned.
Ravi Extensions to Lua 5.3
--------------------------
==========================
Optional Static Typing
++++++++++++++++++++++
----------------------
Ravi allows you to annotate ``local`` variables and function parameters with static types. The supported types and the resulting behaviour are as follows:
``integer``
@ -157,7 +163,7 @@ Following library functions allow creation of array types of defined length.
creates an number array of specified size, and initializes with initial value. The return type is number[]. The size of the array cannot be changed dynamically, i.e. it is fixed to the initial specified size. This allows slices to be created on such arrays.
Type Assertions
+++++++++++++++
---------------
Ravi does not support defining new types, or structured types based on tables. This creates some practical issues when dynamic types are mixed with static types. For example::
local t = { 1,2,3 }
@ -178,7 +184,7 @@ The type assertion operator is a unary operator and binds to the expression foll
For a real example of how type assertions can be used, please have a look at the test program `gaussian2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/gaussian2.lua>`_
Array Slices
++++++++++++
------------
Since release 0.6 Ravi supports array slices. An array slice allows a portion of a Ravi array to be treated as if it is an array - this allows efficient access to the underlying array elements. Following new functions are available:
``table.slice(array, start_index, num_elements)``
@ -195,7 +201,7 @@ Each slice holds an internal reference to the underlying array to ensure that th
For an example use of slices please see the `matmul1.ravi <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/matmul1.ravi>`_ benchmark program in the repository. Note that this feature is highly experimental and not very well tested.
Examples
++++++++
--------
Example of code that works - you can copy this to the command line input::
function tryme()
@ -243,13 +249,12 @@ Another example using arrays. Here the function receives a parameter ``arr`` of
The ``table.numarray(n, initial_value)`` creates a ``number[]`` of specified size and initializes the array with the given initial value.
All type checks are at runtime
++++++++++++++++++++++++++++++
------------------------------
To keep with Lua's dynamic nature Ravi uses a mix of compile type checking and runtime type checks. However due to the dynamic nature of Lua, compilation happens at runtime anyway so effectually all checks are at runtime.
JIT Compilation
---------------
The LLVM based JIT compiler is functional. Most bytecodes other than bit-wise operators are JIT compiled when using LLVM, but there are restrictions as described in compatibility section below. Everything described below relates to using LLVM as the JIT compiler.
JIT API
-------
The LLVM based JIT compiler is functional.
There are two modes of JIT compilation.
auto mode
@ -281,18 +286,20 @@ A JIT api is available with following functions:
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode
boundary; use this option only when you want to use the debug api to step through code line by line
Performance Notes
-----------------
Performance
===========
For performance benchmarks please visit the `Ravi Performance Benchmarks <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-benchmarks.html>`_ page.
To obtain the best possible performance, types must be annotated so that Ravi's JIT compiler can generate efficient code.
Additionally function calls are expensive - as the JIT compiler cannot inline function calls, all function calls go via the Lua call protocol which has a large overhead. This is true for both Lua functions and C functions. For best performance avoid function calls inside loops.
Compatibility with Lua
----------------------
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but there are some differences:
======================
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted:
* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays.
* Values crossing from Lua to Ravi will be subjected to typechecks should these values be assigned to typed variables.
* Upvalues cannot subvert the static typing of local variables (issue #26)
* Upvalues cannot subvert the static typing of local variables (issue #26) when types are annotated.
* Certain Lua limits are reduced due to changed byte code structure. These are described below.
+-----------------+-------------+-------------+
@ -309,31 +316,36 @@ Ravi should be able to run all Lua 5.3 programs in interpreted mode, but there a
| MAXARGLINE | 250 | 120 |
+-----------------+-------------+-------------+
When JIT compilation is enabled some things will not work:
When JIT compilation is enabled there are following additional constraints:
* You cannot yield from a compiled function as compiled code does not support coroutines (issue 14); as a workaround Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode.
* In JITed code tailcalls are implemented as regular calls so unlike Lua VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17)
* Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode.
* In JITed code tailcalls are implemented as regular calls so unlike the interpreter VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17)
Building Ravi
=============
Build Dependencies - LLVM version
---------------------------------
Build Dependencies
------------------
* CMake
* LLVM 3.7 or 3.8 or 3.9
Ravi can be built with or without LLVM. Following versions of LLVM work with Ravi.
* LLVM 3.7 or 3.8 or 3.9 or 4.0
* LLVM 3.5 and 3.6 should also work but have not been recently tested
The build is CMake based.
Unless otherwise noted the instructions below should work for LLVM 3.7 or above.
Unless otherwise noted the instructions below should work for LLVM 3.7 or later.
Building LLVM on Windows
------------------------
I built LLVM from source. I used the following sequence from the VS2015 command window::
I built LLVM from source. I used the following sequence from the VS2017 command window::
cd \github\llvm
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=c:\LLVM -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 14 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\LLVM -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 15 2017 Win64" ..
I then opened the generated solution in VS2015 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter.
I then opened the generated solution in VS2017 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter.
.. note:: Note that if you perform a Release build of LLVM then you will also need to do a Release build of Ravi otherwise you will get link errors.
@ -354,18 +366,18 @@ Assuming that LLVM source has been extracted to ``$HOME/llvm-3.7.0.src`` I follo
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/LLVM -DLLVM_TARGETS_TO_BUILD="X86" ..
make install
Building Ravi
-------------
I am developing Ravi using Visual Studio 2015 Community Edition on Windows 8.1 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
Building Ravi with JIT enabled
------------------------------
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
.. note:: Location of cmake files has moved in LLVM 3.9; the new path is ``$LLVM_INSTALL_DIR/lib/cmake/llvm``.
Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 14 Win64" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 15 2017 Win64" ..
I then open the solution in VS2015 and do a build from there.
I then open the solution in VS2017 and do a build from there.
On Ubuntu I use::
@ -390,8 +402,8 @@ Building without JIT
--------------------
You can omit ``-DLLVM_JIT=ON`` option above to build Ravi with a null JIT implementation.
Static Libraries
----------------
Building Static Libraries
-------------------------
By default the build generates a shared library for Ravi. You can choose to create a static library and statically linked executables by supplying the argument ``-DSTATIC_BUILD=ON`` to CMake.
Build Artifacts
@ -415,64 +427,19 @@ I test the build by running a modified version of Lua 5.3.3 test suite. These te
.. note:: To thoroughly test changes, you need to invoke CMake with ``-DCMAKE_BUILD_TYPE=Debug`` option. This turns on assertions, memory checking, and also enables an internal module used by Lua tests.
Work Plan
---------
* Feb-Jun 2015 - implement JIT compilation using LLVM
* Jun-Jul 2015 - libgccjit based alternative JIT
* 2016 priorties
Roadmap
=======
* 2015 - Implemented JIT compilation using LLVM
* 2015 - Implemented libgccjit based alternative JIT
* 2016 - Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017 - Main priorities are:
* `IDE support (Visual Studio Code) <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
- I would like Ravi to be backward compatible with Lua 5.1 and 5.2 as far as possible
- Lua function inlining
- Improve performance of Ravi
- Additional type annotations
License
-------
=======
MIT License for LLVM version.
Language Syntax - Future work
-----------------------------
Since the reason for introducing optional static typing is to enhance performance primarily - not all types benefit from this capability. In fact it is quite hard to extend this to generic recursive structures such as tables without encurring significant overhead. For instance - even to represent a recursive type in the parser will require dynamic memory allocation and add great overhead to the parser.
From a performance point of view the only types that seem worth specializing are:
* integer (64-bit int)
* number (double)
* array of integers
* array of numbers
Implementation Strategy
-----------------------
I want to build on existing Lua types rather than introducing completely new types to the Lua system. I quite like the minimalist nature of Lua. However, to make the execution efficient I am adding new type specific opcodes and enhancing the Lua parser/code generator to encode these opcodes only when types are known. The new opcodes will execute more efficiently as they will not need to perform type checks. Morever, type specific instructions will lend themselves to more efficient JIT compilation.
I am adding new opcodes that cover arithmetic operations, array operations, variable assignments, etc..
Modifications to Lua Bytecode structure
---------------------------------------
An immediate issue is that the Lua bytecode structure has a 6-bit opcode which is insufficient to hold the various opcodes that I will need. Simply extending the size of this is problematic as then it reduces the space available to the operands A B and C. Furthermore the way Lua bytecodes work means that B and C operands must be 1-bit larger than A - as the extra bit is used to flag whether the operand refers to a constant or a register. (Thanks to Dirk Laurie for pointing this out).
I am amending the bit mapping in the 32-bit instruction to allow 9-bits for the byte-code, 7-bits for operand A, and 8-bits for operands B and C. This means that some of the Lua limits (maximum number of variables in a function, etc.) have to be revised to be lower than the default.
New OpCodes
-----------
The new instructions are specialised for types, and also for register/versus constant. So for example ``OP_RAVI_ADDFI`` means add ``number`` and ``integer``. And ``OP_RAVI_ADDFF`` means add ``number`` and ``number``. The existing Lua opcodes that these are based on define which operands are used.
Example::
local i=0; i=i+1
Above standard Lua code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADD A=0 B=0 C=-2
[2] RETURN A=0 B=1
We add type info using Ravi extensions::
local i:integer=0; i=i+1
Now the code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADDII A=0 B=0 C=-2
[2] RETURN A=0 B=1
Above uses type specialised opcode ``OP_RAVI_ADDII``.

@ -1,5 +1,5 @@
mkdir llvm32
cd llvm32
rem cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM37_32\share\llvm\cmake -DBUILD_STATIC=OFF ..
cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM39\lib\cmake\llvm -DSTATIC_BUILD=OFF ..
cmake -DCMAKE_INSTALL_PREFIX=\d\ravi32 -G "Visual Studio 14" -DLLVM_JIT=ON -DLLVM_DIR=\d\LLVM39_32\lib\cmake\llvm -DSTATIC_BUILD=OFF ..
cd ..

@ -1,4 +1,6 @@
mkdir llvm64
cd llvm64
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake ..
rem pre LLVM 3.9
rem cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 14 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\LLVM37\share\llvm\cmake ..
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -G "Visual Studio 15 2017 Win64" -DLLVM_JIT=ON -DLLVM_DIR=c:\d\LLVM40_64\lib\cmake\llvm ..
cd ..

@ -1,4 +1,4 @@
mkdir nojit64a
cd nojit64a
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 14 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -DCMAKE_BUILD_TYPE=Debug -G "Visual Studio 15 2017 Win64" ..
cd ..

@ -1,4 +1,4 @@
mkdir nojit64
cd nojit64
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 14 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\ravi -DCMAKE_BUILD_TYPE=Release -DSTATIC_BUILD=ON -G "Visual Studio 14 Win64" ..
cd ..

@ -1,3 +1,3 @@
mkdir buildnojit
cd buildnojit
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..
cmake -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/ravi ..

@ -23,7 +23,9 @@
#define twoto(x) (1<<(x))
#define sizenode(t) (twoto((t)->lsizenode))
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
//#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
// Following uses cached hmask which is basically precomputed lmod()
#define hashpow2(t, h) (gnode(t, (h & (t)->hmask)))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define eqshrstr(a,b) ((a) == (b))

@ -1,10 +1,11 @@
; ModuleID = 'inline_getstr.c'
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-S32"
target triple = "i686-pc-windows-gnu"
source_filename = "inline_getstr.c"
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
%struct.TValue = type { %union.Value, i32 }
%union.Value = type { i64 }
%struct.Table = type { %struct.GCObject*, i8, i8, i8, i8, i32, %struct.TValue*, %struct.Node*, %struct.Node*, %struct.Table*, %struct.GCObject*, %struct.RaviArray }
%struct.Table = type { %struct.GCObject*, i8, i8, i8, i8, i32, %struct.TValue*, %struct.Node*, %struct.Node*, %struct.Table*, %struct.GCObject*, %struct.RaviArray, i32 }
%struct.Node = type { %struct.TValue, %union.TKey }
%union.TKey = type { %struct.anon.1 }
%struct.anon.1 = type { %union.Value, i32, i32 }
@ -14,36 +15,33 @@ target triple = "i686-pc-windows-gnu"
%union.anon.2 = type { i64 }
; Function Attrs: nounwind
define %struct.TValue* @ravi_getstr(%struct.Table* %t, %struct.TString* %key) #0 {
define %struct.TValue* @ravi_getstr(%struct.Table* %t, %struct.TString* %key) local_unnamed_addr #0 {
entry:
%hash = getelementptr inbounds %struct.TString, %struct.TString* %key, i32 0, i32 5
%0 = load i32, i32* %hash, align 4, !tbaa !1
%lsizenode = getelementptr inbounds %struct.Table, %struct.Table* %t, i32 0, i32 4
%1 = load i8, i8* %lsizenode, align 1, !tbaa !7
%conv = zext i8 %1 to i32
%shl = shl i32 1, %conv
%sub = add nsw i32 %shl, -1
%and = and i32 %sub, %0
%0 = load i32, i32* %hash, align 8, !tbaa !1
%hmask = getelementptr inbounds %struct.Table, %struct.Table* %t, i32 0, i32 12
%1 = load i32, i32* %hmask, align 4, !tbaa !7
%and = and i32 %1, %0
%node = getelementptr inbounds %struct.Table, %struct.Table* %t, i32 0, i32 7
%2 = load %struct.Node*, %struct.Node** %node, align 4, !tbaa !10
%3 = getelementptr inbounds %struct.Node, %struct.Node* %2, i32 %and, i32 1, i32 0, i32 1
%4 = load i32, i32* %3, align 4, !tbaa !11
%4 = load i32, i32* %3, align 8, !tbaa !11
%cmp = icmp eq i32 %4, 68
br i1 %cmp, label %land.lhs.true, label %if.end
land.lhs.true: ; preds = %entry
%value_ = getelementptr inbounds %struct.Node, %struct.Node* %2, i32 %and, i32 1, i32 0, i32 0
%5 = bitcast %union.Value* %value_ to %struct.TString**
%6 = load %struct.TString*, %struct.TString** %5, align 4, !tbaa !13
%cmp2 = icmp eq %struct.TString* %6, %key
br i1 %cmp2, label %if.then, label %if.end
%6 = load %struct.TString*, %struct.TString** %5, align 8, !tbaa !13
%cmp1 = icmp eq %struct.TString* %6, %key
br i1 %cmp1, label %if.then, label %if.end
if.then: ; preds = %land.lhs.true
%i_val = getelementptr inbounds %struct.Node, %struct.Node* %2, i32 %and, i32 0
br label %cleanup
if.end: ; preds = %land.lhs.true, %entry
%call = tail call %struct.TValue* @luaH_getstr(%struct.Table* %t, %struct.TString* %key) #2
%call = tail call %struct.TValue* @luaH_getstr(%struct.Table* nonnull %t, %struct.TString* nonnull %key) #2
br label %cleanup
cleanup: ; preds = %if.end, %if.then
@ -51,23 +49,23 @@ cleanup: ; preds = %if.end, %if.then
ret %struct.TValue* %retval.0
}
declare %struct.TValue* @luaH_getstr(%struct.Table*, %struct.TString*) #1
declare %struct.TValue* @luaH_getstr(%struct.Table*, %struct.TString*) local_unnamed_addr #1
attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.7.0 (trunk)"}
!0 = !{!"clang version 3.9.0 (trunk)"}
!1 = !{!2, !6, i64 8}
!2 = !{!"TString", !3, i64 0, !4, i64 4, !4, i64 5, !4, i64 6, !4, i64 7, !6, i64 8, !4, i64 16}
!3 = !{!"any pointer", !4, i64 0}
!4 = !{!"omnipotent char", !5, i64 0}
!5 = !{!"Simple C/C++ TBAA"}
!6 = !{!"int", !4, i64 0}
!7 = !{!8, !4, i64 7}
!8 = !{!"Table", !3, i64 0, !4, i64 4, !4, i64 5, !4, i64 6, !4, i64 7, !6, i64 8, !3, i64 12, !3, i64 16, !3, i64 20, !3, i64 24, !3, i64 28, !9, i64 32}
!7 = !{!8, !6, i64 48}
!8 = !{!"Table", !3, i64 0, !4, i64 4, !4, i64 5, !4, i64 6, !4, i64 7, !6, i64 8, !3, i64 12, !3, i64 16, !3, i64 20, !3, i64 24, !3, i64 28, !9, i64 32, !6, i64 48}
!9 = !{!"RaviArray", !3, i64 0, !4, i64 4, !6, i64 8, !6, i64 12}
!10 = !{!8, !3, i64 16}
!11 = !{!12, !6, i64 8}

@ -204,6 +204,7 @@ struct Table {
struct Table *metatable;
struct GCObject *gclist;
struct RaviArray ravi_array;
unsigned int hmask;
};
/* lzio.h */
@ -312,9 +313,28 @@ struct UpVal {
} u;
};
/*
** Union of all collectable objects (only for conversions)
*/
union GCUnion {
struct GCObject gc; /* common header */
struct TString ts;
struct Udata u;
union Closure cl;
struct Table h;
struct Proto p;
struct lua_State th; /* thread */
};
#define rttype(o) ((o)->tt_)
#define BIT_ISCOLLECTABLE (1 << 6)
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
#define upisopen(up) ((up)->v != &(up)->u.value)
#define val_(o) ((o)->value_)
#define cast(t, exp) ((t)(exp))
#define cast_u(o) cast(union GCUnion *, (o))
#define gco2t(o) &((cast_u(o))->h)
#define hvalue(o) gco2t(val_(o).gc)
#endif

@ -0,0 +1,6 @@
#include "lua_hdr.h"
int tablevalue(struct TValue *v)
{
return (hvalue(v))->sizearray;
}

@ -0,0 +1,37 @@
; ModuleID = 'tab.c'
source_filename = "tab.c"
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
target triple = "i686-pc-windows-msvc"
%struct.TValue = type { %union.Value, i32 }
%union.Value = type { i64 }
%struct.Table = type { %struct.GCObject*, i8, i8, i8, i8, i32, %struct.TValue*, %struct.Node*, %struct.Node*, %struct.Table*, %struct.GCObject*, %struct.RaviArray, i32 }
%struct.Node = type { %struct.TValue, %union.TKey }
%union.TKey = type { %struct.anon.2 }
%struct.anon.2 = type { %union.Value, i32, i32 }
%struct.GCObject = type { %struct.GCObject*, i8, i8 }
%struct.RaviArray = type { i8*, i32, i32, i32 }
; Function Attrs: norecurse nounwind readonly
define i32 @tablevalue(%struct.TValue* nocapture readonly %v) local_unnamed_addr #0 {
entry:
%0 = bitcast %struct.TValue* %v to %struct.Table**
%1 = load %struct.Table*, %struct.Table** %0, align 8, !tbaa !1
%sizearray = getelementptr inbounds %struct.Table, %struct.Table* %1, i32 0, i32 5
%2 = load i32, i32* %sizearray, align 8, !tbaa !5
ret i32 %2
}
attributes #0 = { norecurse nounwind readonly "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-features"="+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0}
!0 = !{!"clang version 3.9.0 (trunk)"}
!1 = !{!2, !2, i64 0}
!2 = !{!"any pointer", !3, i64 0}
!3 = !{!"omnipotent char", !4, i64 0}
!4 = !{!"Simple C/C++ TBAA"}
!5 = !{!6, !7, i64 8}
!6 = !{!"Table", !2, i64 0, !3, i64 4, !3, i64 5, !3, i64 6, !3, i64 7, !7, i64 8, !2, i64 12, !2, i64 16, !2, i64 20, !2, i64 24, !2, i64 28, !8, i64 32, !7, i64 48}
!7 = !{!"int", !3, i64 0}
!8 = !{!"RaviArray", !2, i64 0, !3, i64 4, !7, i64 8, !7, i64 12}

@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@ -16,10 +16,18 @@
/* extra error code for 'luaL_load' */
/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
/* key, in the registry, for table of loaded modules */
#define LUA_LOADED_TABLE "_LOADED"
/* key, in the registry, for table of preloaded loaders */
#define LUA_PRELOAD_TABLE "_PRELOAD"
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;

@ -36,7 +36,7 @@ typedef enum BinOpr {
OPR_NOBINOPR
} BinOpr;
/** RAVI change */
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_TO_INTEGER,
OPR_TO_NUMBER, OPR_TO_INTARRAY, OPR_TO_NUMARRAY, OPR_TO_TABLE, OPR_NOUNOPR } UnOpr;

@ -34,6 +34,7 @@ enum RESERVED {
TK_SHL, TK_SHR,
TK_DBCOLON, TK_EOS,
TK_FLT, TK_INT, TK_NAME, TK_STRING,
/** RAVI extensions */
TK_TO_INTEGER, TK_TO_NUMBER, TK_TO_INTARRAY, TK_TO_NUMARRAY,
TK_TO_TABLE
};

@ -82,6 +82,7 @@ typedef LUAI_UACINT l_uacInt;
/* internal assertions for in-house debugging */
#if defined(lua_assert)
/** RAVI changes */
#if !defined(RAVI_OPTION_STRING1)
#define RAVI_OPTION_STRING1 " assertions"
#endif
@ -95,6 +96,7 @@ typedef LUAI_UACINT l_uacInt;
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
#define lua_longassert(c) ((void)0)
/** RVAI changes */
#define RAVI_OPTION_STRING1
#define RAVI_OPTION_STRING2
#endif

@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $
** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@ -57,7 +57,7 @@
/* Variant tags for numbers */
#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */
#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */
/** RAVI table sunbtypes **/
#define RAVI_TIARRAY (LUA_TTABLE | (1 << 4)) /* Ravi int array */
#define RAVI_TFARRAY (LUA_TTABLE | (2 << 4)) /* Ravi float array */
@ -151,7 +151,7 @@ typedef struct lua_TValue {
#define ttisstring(o) checktype((o), LUA_TSTRING)
#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR))
#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR))
/* Ravi change: we support two sub types of table type
/* RAVI change: we support two sub types of table type
and hence need to distinguish between the types.
ttistable() returns true for all table types
ttisLtable() only returns true if the value is a Lua table
@ -265,17 +265,18 @@ typedef struct lua_TValue {
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(L,io); }
/** RAVI extension **/
#define setiarrayvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TIARRAY)); \
checkliveness(L,io); }
/** RAVI extension **/
#define setfarrayvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(RAVI_TFARRAY)); \
checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@ -403,7 +404,7 @@ typedef union UUdata {
io->value_ = iu->user_; settt_(io, iu->ttuv_); \
checkliveness(L,io); }
/* Following are the types we will use
/* RAVI: Following are the types we will use
** use in parsing. The rationale for types is
** performance - as of now these are the only types that
** we care about from a performance point of view - if any
@ -445,6 +446,7 @@ typedef struct LocVar {
ravitype_t ravi_type; /* RAVI type of the variable - RAVI_TANY if unknown */
} LocVar;
/** RAVI changes start */
typedef enum {
RAVI_JIT_NOT_COMPILED = 0,
RAVI_JIT_CANT_COMPILE = 1,
@ -463,6 +465,7 @@ typedef struct RaviJITProto {
void *jit_data;
lua_CFunction jit_function;
} RaviJITProto;
/** RAVI changes end */
/*
** Function Prototypes
@ -470,7 +473,7 @@ typedef struct RaviJITProto {
typedef struct Proto {
CommonHeader;
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */
lu_byte is_vararg;
lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */
@ -489,7 +492,7 @@ typedef struct Proto {
struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */
GCObject *gclist;
/* RAVI */
/* RAVI extension */
RaviJITProto ravi_jit;
} Proto;
@ -558,12 +561,13 @@ typedef struct Node {
TKey i_key;
} Node;
/** RAVI extension */
typedef enum RaviArrayModifer {
RAVI_ARRAY_SLICE = 1,
RAVI_ARRAY_FIXEDSIZE = 2
} RaviArrayModifier;
/** RAVI extension */
typedef struct RaviArray {
char *data;
unsigned int len; /* RAVI len specialization */
@ -582,7 +586,9 @@ typedef struct Table {
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
/** RAVI extension */
RaviArray ravi_array;
unsigned int hmask; /* Hash part mask (size of hash part - 1) - borrowed from LuaJIT */
} Table;

@ -1,5 +1,5 @@
/*
** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $
** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@ -35,6 +35,7 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/*
** size and position of opcode arguments.
*/
/** RAVI changes **/
#define SIZE_C 8
#define SIZE_B 8
#define SIZE_Bx (SIZE_C + SIZE_B)
@ -139,7 +140,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK)
#if !defined(MAXINDEXRK) /* (for debugging only) */
#define MAXINDEXRK (BITRK - 1)
#endif
/* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK)

@ -66,7 +66,7 @@ typedef struct expdesc {
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
ravitype_t key_type; /* key type */
ravitype_t key_type; /* RAVI change: key type */
} ind;
} u;
int t; /* patch list of 'exit when true' */
@ -238,11 +238,10 @@ typedef struct FuncState {
LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
LUAI_FUNC LClosure *raviY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
/** RAVI extensions **/
LUAI_FUNC const char *raviY_typename(ravitype_t tt);
/* Special printf that recognises following conversions:

@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@ -23,7 +23,7 @@
**
** 'allgc': all objects not marked for finalization;
** 'finobj': all objects marked for finalization;
** 'tobefnz': all objects ready to be finalized;
** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
@ -34,7 +34,7 @@ struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
@ -66,7 +66,7 @@ typedef struct stringtable {
** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that
** case, the actual 'func' value is saved in field 'extra'.
** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation
** function can be called with the correct top.
@ -88,9 +88,9 @@ typedef struct CallInfo {
} u;
ptrdiff_t extra;
short nresults; /* expected number of results from this function */
lu_byte callstatus;
lu_byte jitstatus; /* Only valid if Lua function - if 1 means JITed - RAVI extension */
short stacklevel; /* Ravi extension - stack level, bottom level is 0 */
unsigned short callstatus;
unsigned short stacklevel; /* RAVI extension - stack level, bottom level is 0 */
lu_byte jitstatus; /* RAVI extension: Only valid if Lua function - if 1 means JITed - RAVI extension */
} CallInfo;
@ -106,14 +106,17 @@ typedef struct CallInfo {
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_LEQ (1<<7) /* using __lt for __le */
#define CIST_FIN (1<<8) /* call is running a finalizer */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
/** RAVI extension **/
#define isJITed(ci) ((ci)->jitstatus)
/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
#define getoah(st) ((st) & CIST_OAH)
/** RAVI extension **/
typedef struct ravi_State ravi_State;
/*
@ -154,12 +157,17 @@ typedef struct global_State {
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
/* RAVI */
/* RAVI additions */
ravi_State *ravi_state;
ravi_Writeline ravi_writeline;
ravi_Writestring ravi_writestring;
ravi_Writestringerror ravi_writestringerror;
void * ravi_debugger_data;
#if RAVI_BYTECODE_PROFILING_ENABLED
unsigned long long *ravi_profile1;
unsigned long long *ravi_profile2;
unsigned long long ravi_prev_time;
#endif
} global_State;
@ -187,8 +195,16 @@ struct lua_State {
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
/** RAVI difference - changing type of hookmask
** changes to JIT definitions and possibly code. This is
** pending
*/
lu_byte hookmask;
lu_byte allowhook;
/** RAVI difference - movig nci requires
** changes to JIT definitions and possibly code. This is
** pending
*/
unsigned short nci; /* number of items in 'ci' list */
};
@ -220,6 +236,7 @@ union GCUnion {
#define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))
#define gco2cl(o) \
check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
/** RAVI change - we have table sub types in RAVI **/
#define gco2t(o) check_exp(novariant((o)->tt) == LUA_TTABLE, &((cast_u(o))->h))
#define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
#define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))
@ -239,7 +256,7 @@ LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
/* Ravi addition - this is the default implementation behind writing to stderr */
/* RAVI addition - this is the default implementation behind writing to stderr */
LUAI_FUNC void raviE_default_writestringerror(const char *fmt, const char *p);

@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $
** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@ -9,12 +9,13 @@
#include "lobject.h"
#define gnode(t,i) (&(t)->node[i])
#define gval(n) (&(n)->i_val)
#define gnext(n) ((n)->i_key.nk.next)
/* 'const' to avoid wrong writings that can mess up field 'next' */
/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
/*
@ -26,38 +27,61 @@
#define invalidateTMcache(t) ((t)->flags = 0)
/* true when 't' is using 'dummynode' as its hash part */
#define isdummy(t) ((t)->lastfree == NULL)
/* allocated size for hash nodes */
#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
#if defined(RAVI_ENABLED)
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
/** RAVI change start - attempt to inline some functions **/
#define NEW_HASH 1
#if NEW_HASH
/*
Like LuaJIT we use a pre-computed hmask to minimise the number of steps
required to get to a node in the hash table
*/
#define hashpow2(t, h) (gnode(t, (h & (t)->hmask)))
#define hashstr(t, str) hashpow2(t, (str)->hash)
#define hashboolean(t, p) hashpow2(t, p)
#define hashint(t, i) hashpow2(t, i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t, n) (gnode(t, ((n) % ((t)->hmask|1))))
#define hashpointer(t, p) hashmod(t, point2uint(p))
#else
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p))
#endif
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
#if defined(RAVI_ENABLED)
/*
** search function for short strings
*/
static inline const TValue *luaH_getshortstr(Table *t, TString *key) {
static RAVI_ALWAYS_INLINE const TValue *luaH_getshortstr(Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
@ -178,7 +202,7 @@ LUAI_FUNC void raviH_get_integer_array_rawdata(lua_State *L, Table *t, lua_Integ
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (Node *n);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif

@ -1,5 +1,5 @@
/*
** $Id: ltests.h,v 2.49 2015/09/22 14:18:24 roberto Exp $
** $Id: ltests.h,v 2.49 2015/09/22 14:18:24 roberto Exp roberto $
** Internal Header for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -30,7 +30,6 @@
/* turn on assertions */
#undef NDEBUG
#include <assert.h>
#define lua_assert(c) assert(c)
#if !defined(RAVI_OPTION_STRING1)
@ -106,7 +105,9 @@ LUA_API Memcontrol* luaB_getmemcontrol(void);
#if defined(lua_c)
#define luaL_newstate() lua_newstate(debug_realloc, luaB_getmemcontrol())
#define luaL_openlibs(L) \
{ (luaL_openlibs)(L); luaL_requiref(L, "T", luaB_opentests, 1); }
{ (luaL_openlibs)(L); \
luaL_requiref(L, "T", luaB_opentests, 1); \
lua_pop(L, 1); }
#endif
@ -116,6 +117,7 @@ LUA_API Memcontrol* luaB_getmemcontrol(void);
#undef LUAL_BUFFERSIZE
#define LUAL_BUFFERSIZE 23
#define MINSTRTABSIZE 2
//#define MAXINDEXRK 1
/* make stack-overflow tests run faster */

@ -43,7 +43,7 @@ typedef enum {
TM_N /* number of elements in the enum */
} TMS;
/* The macro metamethod absent tests whether it is known that a metatable
/* RAVI change: the macro metamethod absent tests whether it is known that a metatable
* lacks a metamethod. This is true if a) metatable is NULL, or b) the bit
* related to the metamethod is set in t->flags
*/
@ -60,7 +60,7 @@ LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
/* Extended version that distinguishes between table subtypes*/
/* RAVI change: extended version that distinguishes between table subtypes*/
LUAI_FUNC const char *raviT_objtypename(lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);

@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "3"
#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION "Ravi " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2016 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2016 Dibyendu Majumdar"
#define LUA_COPYRIGHT LUA_RELEASE "\nCopyright (C) 1994-2017 Lua.org, PUC-Rio\nPortions Copyright (C) 2015-2017 Dibyendu Majumdar"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes, Dibyendu Majumdar"
@ -123,9 +123,11 @@ typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/** RAVI change start **/
typedef void(*ravi_Writestring)(const char *s, size_t len);
typedef void(*ravi_Writeline)(void);
typedef void(*ravi_Writestringerror)(const char *fmt, const char *p);
/** RAVI change end **/
/*
** generic extra include file
@ -179,9 +181,11 @@ LUA_API int (lua_isinteger) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
/* This is a Ravi extension - it is similar to lua_typename() except
that it provides more granular type information, and also uses
metamethod __name() if available for userdata and table types */
/* RAVI change:
** This is a Ravi extension - it is similar to lua_typename() except
** that it provides more granular type information, and also uses
** metamethod __name() if available for userdata and table types
*/
LUA_API const char * (ravi_typename) (lua_State *L, int idx);
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
@ -458,7 +462,7 @@ struct lua_Debug {
char isvararg; /* (u) */
char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */
short stacklevel; /* Ravi: Current stack level within the Lua State - base level is 0 */
short stacklevel; /* RAVI change: Current stack level within the Lua State - base level is 0 */
/* private part */
struct CallInfo *i_ci; /* active function */
};
@ -553,11 +557,12 @@ LUA_API void ravi_set_debuglevel(int level);
#define RAVI_DEBUG_STACK(p) if ((ravi_parser_debug & 8) != 0) {p;} else {}
#define RAVI_ENABLED 1
#define RAVI_BYTECODE_PROFILING_ENABLED 0
/******************************************************************************
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@ -158,6 +158,18 @@
** ===================================================================
*/
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
*/
#define LUA_PATH_SEP ";"
#define LUA_PATH_MARK "?"
#define LUA_EXEC_DIR "!"
/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries.
@ -265,6 +277,7 @@
*/
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
defined(__ELF__) /* { */
/** RAVI change **/
#define LUAI_FUNC /* __attribute__((visibility("hidden")))*/ extern
#else /* }{ */
#define LUAI_FUNC extern
@ -404,7 +417,7 @@
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number.
@@ l_mathlim(x) corrects limit name 'x' to the proper float type
** by prefixing it with one of FLT/DBL/LDBL.
@ -421,7 +434,8 @@
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
#define lua_number2str(s,sz,n) \
l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
@ -498,7 +512,7 @@
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
@@ LUAI_UACINT is the result of an 'usual argument conversion'
@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers.
@ -511,10 +525,12 @@
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER
#define lua_integer2str(s,sz,n) \
l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
/*
** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison)
@ -606,13 +622,14 @@
/*
@@ lua_number2strx converts a float to an hexadecimal numeric string.
@@ lua_number2strx converts a float to an hexadecimal numeric string.
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
#define lua_number2strx(L,b,sz,f,n) \
((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif
@ -728,11 +745,11 @@
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space. (For long double,
** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
** smaller buffer would force a memory allocation for each call to
** 'string.format'.)
*/
#if defined(LUA_FLOAT_LONGDOUBLE)
#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
#define LUAL_BUFFERSIZE 8192
#else
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
@ -759,10 +776,45 @@
** without modifying the main part of the file.
*/
/** RAVI additions below **/
#if _WIN32 && _MSC_VER < 1900
#define snprintf _snprintf
#endif
#if defined(__GNUC__)
#define RAVI_NORETURN __attribute__((noreturn))
#define RAVI_INLINE inline
#define RAVI_ALWAYS_INLINE inline __attribute__((always_inline))
#define RAVI_LIKELY(x) __builtin_expect(!!(x), 1)
#define RAVI_UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif
#if defined(__clang__)
#define RAVI_NORETURN __attribute__((noreturn))
#define RAVI_INLINE inline
#define RAVI_ALWAYS_INLINE inline __attribute__((always_inline))
#define RAVI_LIKELY(x) __builtin_expect(!!(x), 1)
#define RAVI_UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif
#if defined(_MSC_VER)
#define RAVI_NORETURN __declspec(noreturn)
#define RAVI_INLINE __inline
#define RAVI_ALWAYS_INLINE __forceinline
#define RAVI_LIKELY(x) (x)
#define RAVI_UNLIKELY(x) (x)
#endif
#endif

@ -1,5 +1,5 @@
/*
** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@ -11,6 +11,9 @@
#include "lua.h"
/* version suffix for environment variable names */
#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
LUAMOD_API int (luaopen_base) (lua_State *L);
@ -44,6 +47,7 @@ LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package"
LUAMOD_API int (luaopen_package) (lua_State *L);
/** RAVI change start **/
#define LUA_RAVILIBNAME "ravi"
LUAMOD_API int (raviopen_llvmjit)(lua_State *L);
@ -51,7 +55,7 @@ LUAMOD_API int (raviopen_llvmjit)(lua_State *L);
#define LUA_LLVMLIBNAME "llvm"
LUAMOD_API int (raviopen_llvmluaapi)(lua_State *L);
#endif
/** RAVI change end */
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
@ -59,8 +63,10 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
/** RAVI change start **/
#define RAVI_OPTION_STRING1
#define RAVI_OPTION_STRING2
/** RAVI change end **/
#endif

@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@ -38,10 +38,10 @@
#define tonumber(o,n) \
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
(RAVI_LIKELY(ttisfloat(o)) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
#define tointeger(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
(RAVI_LIKELY(ttisinteger(o)) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
@ -63,6 +63,8 @@
/*
** standard implementation for 'gettable'
** RAVI change - renamed as we need luaV_gettable to be
** an exported function
*/
#define luaV_fastgettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
@ -86,7 +88,10 @@
setobj2t(L, cast(TValue *,slot), v), \
1)))
/*
** RAVI change - renamed as we need luaV_settable to be
** an exported function
*/
#define luaV_fastsettable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
@ -98,17 +103,19 @@ LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
/** RAVI changes start **/
LUAI_FUNC int luaV_tointeger_(const TValue *obj, lua_Integer *p);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
StkId val);
/** RAVI changed end **/
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
/* The int return value is a Ravi extension */
/* RAVI change: the int return value is a Ravi extension */
LUAI_FUNC int luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y);
@ -116,7 +123,7 @@ LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
/* RAVI changes for JIT */
/* RAVI changes start for JIT */
/* The following expose some of the VM opcodes for the JIT compiler */
LUAI_FUNC int luaV_forlimit(const TValue *obj, lua_Integer *p, lua_Integer step,
int *stopnow);

@ -27,7 +27,7 @@
#include "llvm/Config/llvm-config.h"
#if (LLVM_VERSION_MAJOR != 3 || LLVM_VERSION_MINOR < 5)
#if (LLVM_VERSION_MAJOR < 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5)
#error Unsupported LLVM version
#endif
@ -46,7 +46,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Metadata.h"
#if LLVM_VERSION_MINOR < 7
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
#include "llvm/PassManager.h"
#else
#include "llvm/IR/LegacyPassManager.h"

@ -351,6 +351,7 @@ struct LuaLLVMTypes {
llvm::MDNode *tbaa_Table_array;
llvm::MDNode *tbaa_Table_flags;
llvm::MDNode *tbaa_Table_metatable;
llvm::MDNode *tbaa_Table_hmask;
};
// The hierarchy of objects
@ -472,7 +473,8 @@ class RaviJITFunction {
const std::string &name() const { return name_; }
llvm::Function *function() const { return function_; }
llvm::Module *module() const { return module_->module(); }
RaviJITModule *raviModule() const { return module_.get(); }
std::shared_ptr<RaviJITModule> raviModule() const { return module_; }
llvm::ExecutionEngine *engine() const { return module_->engine(); }
RaviJITState *owner() const { return module_->owner(); }
// This method retrieves the JITed function from the
@ -527,6 +529,10 @@ class RaviJITState {
// instruction; this is expensive!
bool tracehook_enabled_;
// Count of modules allocated
// Used to debug module deallocation
size_t allocated_modules_;
public:
RaviJITState();
~RaviJITState();
@ -561,6 +567,9 @@ class RaviJITState {
void set_gcstep(int value) { gc_step_ = value > 0 ? value : gc_step_; }
bool is_tracehook_enabled() const { return tracehook_enabled_; }
void set_tracehook_enabled(bool value) { tracehook_enabled_ = value; }
void incr_allocated_modules() { allocated_modules_++; }
void decr_allocated_modules() { allocated_modules_--; }
size_t allocated_modules() const { return allocated_modules_; }
};
// To optimise fornum loops
@ -748,6 +757,9 @@ class RaviCodeGenerator {
llvm::Value *arg3, llvm::Value *arg4,
llvm::Value *arg5);
void attach_branch_weights(RaviFunctionDef *def, llvm::Instruction *ins,
uint32_t true_branch, uint32_t false_branch);
void emit_raise_lua_error(RaviFunctionDef *def, const char *str);
// Add extern declarations for Lua functions we need to call
@ -797,9 +809,11 @@ class RaviCodeGenerator {
// The return value is a boolean type as a result of
// integer comparison result which is i1 in LLVM
llvm::Value *emit_is_not_value_of_type_class(
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode,
const char *varname = "value.not.typeof");
RaviFunctionDef *def, llvm::Value *value_type, LuaTypeCode lua_typecode,
const char *varname = "value.not.typeof");
// emit code for LClosure *cl = clLvalue(ci->func)
// this is same as:
// emit code for (LClosure *)ci->func->value_.gc
llvm::Instruction *emit_gep_ci_func_value_gc_asLClosure(RaviFunctionDef *def);
@ -832,8 +846,10 @@ class RaviCodeGenerator {
// emit code to obtain address of constant at locatiion B
llvm::Value *emit_gep_constant(RaviFunctionDef *def, int B);
#if 0
llvm::Value *emit_is_jit_call(RaviFunctionDef *def, llvm::Value *ci);
llvm::Value *emit_ci_is_Lua(RaviFunctionDef *def, llvm::Value *ci);
#endif
// obtain address of L->top
llvm::Value *emit_gep_L_top(RaviFunctionDef *def);
@ -862,25 +878,39 @@ class RaviCodeGenerator {
llvm::Instruction *emit_load_reg_h(RaviFunctionDef *def, llvm::Value *ra);
// Gets the size of the hash table
// This is the sizenode() macro in lobject.h
llvm::Value *emit_table_get_hashsize(RaviFunctionDef *def,
llvm::Value *table);
// Gets the location of the hash node for given key and table size
// Gets the location of the hash node for given string key
// return value is the offset into the node array
llvm::Value *emit_table_get_hashstr(RaviFunctionDef *def, llvm::Value *table,
TString *key);
// Gets access to the Table's node array (t->node)
llvm::Value *emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *table);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// type of the value stored at the node - return value is of type int
// and is the type information stored in TValue->tt field.
llvm::Value *emit_table_get_keytype(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the string value stored at the node - return value is of type TString*
llvm::Value *emit_table_get_strkey(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the pointer to value stored at the node - return value is of type TValue*
llvm::Value *emit_table_get_value(RaviFunctionDef *def, llvm::Value *node,
llvm::Value *index);
// Gets the size of the table's array part
llvm::Value *emit_table_get_arraysize(RaviFunctionDef *def,
llvm::Value *table);
@ -1015,6 +1045,9 @@ class RaviCodeGenerator {
void emit_ARITH(RaviFunctionDef *def, int A, int B, int C, OpCode op, TMS tms,
int pc);
void emit_ARITH_new(RaviFunctionDef *def, int A, int B, int C, OpCode op,
TMS tms, int pc);
void emit_MOD(RaviFunctionDef *def, int A, int B, int C, int pc);
void emit_IDIV(RaviFunctionDef *def, int A, int B, int C, int pc);
@ -1101,7 +1134,8 @@ class RaviCodeGenerator {
void emit_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_GETTABLE_SK(RaviFunctionDef *def, int A, int B, int C, int pc);
void emit_GETTABLE_SK(RaviFunctionDef *def, int A, int B, int C, int pc,
TString *key);
void emit_GETTABLE_I(RaviFunctionDef *def, int A, int B, int C, int pc);
@ -1118,8 +1152,8 @@ class RaviCodeGenerator {
void emit_common_GETTABLE_S(RaviFunctionDef *def, int A, int B, int C,
TString *key);
void emit_common_GETTABLE_S_(RaviFunctionDef *def, int A, llvm::Value *rb, int C,
TString *key);
void emit_common_GETTABLE_S_(RaviFunctionDef *def, int A, llvm::Value *rb,
int C, TString *key);
void emit_GETUPVAL(RaviFunctionDef *def, int A, int B, int pc);
@ -1206,8 +1240,8 @@ class RaviCodeGenerator {
void emit_BNOT_I(RaviFunctionDef *def, int A, int B, int pc);
void emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, int A, int B,
int C, int pc);
void emit_BOR_BXOR_BAND(RaviFunctionDef *def, OpCode op, int A, int B, int C,
int pc);
void emit_BNOT(RaviFunctionDef *def, int A, int B, int pc);

@ -0,0 +1,15 @@
#ifndef RAVI_PROFILE_H
#define RAVI_PROFILE_H
#include "lua.h"
#include "lopcodes.h"
#if RAVI_BYTECODE_PROFILING_ENABLED
LUAI_FUNC void raviV_init_profiledata(lua_State *L);
LUAI_FUNC void raviV_add_profiledata(lua_State *L, OpCode opcode);
LUAI_FUNC void raviV_destroy_profiledata(lua_State *L);
#endif
#endif

@ -1,5 +1,6 @@
#!../lua
-- $Id: all.lua,v 1.94 2015/09/17 16:45:19 roberto Exp $
-- $Id: all.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice at the end of this file
local version = "Ravi 5.3"
if _VERSION ~= version then
@ -265,3 +266,30 @@ end
print("final OK !!!")
--[[
*****************************************************************************
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*****************************************************************************
]]

@ -1,4 +1,5 @@
-- $Id: api.lua,v 1.146 2016/01/07 16:45:45 roberto Exp $
-- $Id: api.lua,v 1.147 2016/11/07 13:06:25 roberto Exp $
-- See Copyright Notice in file all.lua
if T==nil then
(Message or print)('\n >>> testC not active: skipping API tests <<<\n')

@ -1,4 +1,5 @@
-- $Id: attrib.lua,v 1.64 2016/01/07 16:46:37 roberto Exp $
-- $Id: attrib.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing require"

@ -1,4 +1,5 @@
-- $Id: big.lua,v 1.31 2014/12/26 17:20:53 roberto Exp $
-- $Id: big.lua,v 1.32 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
if _soft then
return 'a'

@ -1,4 +1,5 @@
-- $Id: bitwise.lua,v 1.25 2015/04/30 14:15:57 roberto Exp $
-- $Id: bitwise.lua,v 1.26 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print("testing bitwise operations")

@ -1,4 +1,5 @@
-- $Id: calls.lua,v 1.59 2015/11/13 13:46:31 roberto Exp $
-- $Id: calls.lua,v 1.60 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print("testing functions and calls")

@ -1,4 +1,5 @@
-- $Id: closure.lua,v 1.58 2014/12/26 17:20:53 roberto Exp $
-- $Id: closure.lua,v 1.59 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing closures"

@ -1,4 +1,5 @@
-- $Id: code.lua,v 1.41 2014/12/26 17:18:43 roberto Exp $
-- $Id: code.lua,v 1.42 2016/11/07 13:04:32 roberto Exp $
-- See Copyright Notice in file all.lua
if T==nil then
(Message or print)('\n >>> testC not active: skipping opcode tests <<<\n')
@ -116,7 +117,7 @@ check(function () return not not 1 end, 'LOADBOOL', 'RETURN')
check(function ()
local a,b,c,d
a = b*2
c[4], a[b] = -((a + d/-20.5 - a[b]) ^ a.x), b
c[2], a[b] = -((a + d/2 - a[b]) ^ a.x), b
end,
'LOADNIL',
'MUL',
@ -127,17 +128,25 @@ end,
-- direct access to constants
check(function ()
local a,b
a.x = 0
a.x = 3.2
a.x = b
a[b] = 'y'
a[b] = 'x'
end,
'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN')
check(function ()
local a,b
a = 1 - a
b = 1/a
b = 5+4
b = 5-4
end,
'LOADNIL', 'SUB', 'DIV', 'LOADK', 'RETURN')
check(function ()
local a,b
a[true] = false
end,
'LOADNIL',
'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK',
'SETTABLE', 'RETURN')
'LOADNIL', 'SETTABLE', 'RETURN')
-- constant folding
@ -165,7 +174,7 @@ checkK(function () return ((100 << 6) << -4) >> 2 end, 100)
-- no foldings
check(function () return -0.0 end, 'LOADK', 'UNM', 'RETURN')
--check(function () return 3/0 end, 'DIV', 'RETURN')
check(function () return 3/0 end, 'DIVII', 'RETURN')
check(function () return 0%0 end, 'MOD', 'RETURN')
check(function () return -4//0 end, 'IDIV', 'RETURN')
@ -192,7 +201,7 @@ end,
checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
check(function () if a==nil then a=1 end end,
check(function () if a==nil then a='a' end end,
'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
-- de morgan
@ -204,11 +213,11 @@ checkequal(function (l) local a; return 0 <= a and a <= l end,
-- if-goto optimizations
check(function (a)
if a == 1 then goto l1
elseif a == 2 then goto l2
elseif a == 3 then goto l2
else if a == 4 then goto l3
check(function (a, b, c, d, e)
if a == b then goto l1
elseif a == c then goto l2
elseif a == d then goto l2
else if a == e then goto l3
else goto l3
end
end

@ -1,4 +1,5 @@
-- $Id: constructs.lua,v 1.40 2015/10/08 15:58:10 roberto Exp $
-- $Id: constructs.lua,v 1.41 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
;;print "testing syntax";;

@ -1,4 +1,5 @@
-- $Id: coroutine.lua,v 1.40 2015/10/12 16:38:57 roberto Exp $
-- $Id: coroutine.lua,v 1.42 2016/11/07 13:03:20 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing coroutines"
@ -260,6 +261,20 @@ assert(coroutine.resume(co, co) == false)
assert(coroutine.resume(co, co) == false)
-- other old bug when attempting to resume itself
-- (trigger C-code assertions)
do
local A = coroutine.running()
local B = coroutine.create(function() return coroutine.resume(A) end)
local st, res = coroutine.resume(B)
assert(st == true and res == false)
A = coroutine.wrap(function() return pcall(A, 1) end)
st, res = A()
assert(not st and string.find(res, "non%-suspended"))
end
-- attempt to resume 'normal' coroutine
local co1, co2
co1 = coroutine.create(function () return co2() end)
@ -293,7 +308,7 @@ assert(_G.f() == 11)
assert(_G.f() == 12)
if not T or ravi and ravi.auto() then
if not T or ravi and ravi.auto() and not ravi.tracehook() then
(Message or print)('\n >>> testC not active: skipping yield/hook tests <<<\n')
else
print "testing yields inside hooks"
@ -351,7 +366,7 @@ else
_G.XX = nil;
local c = 0
repeat c = c + 1; local a = co() until a == 10
assert(_G.XX == 20 and c == 10)
assert(_G.XX == 20 and c >= 5)
co = coroutine.wrap(function ()
T.sethook("yield 0", "", 2); foo(); return 10 end)
@ -359,7 +374,7 @@ else
_G.XX = nil;
local c = 0
repeat c = c + 1; local a = co() until a == 10
assert(_G.XX == 20 and c == 5)
assert(_G.XX == 20 and c >= 5)
_G.X = nil; _G.XX = nil
do

@ -1,4 +1,5 @@
-- $Id: db.lua,v 1.78 2015/10/02 15:47:27 roberto Exp $
-- $Id: db.lua,v 1.79 2016/11/07 13:02:34 roberto Exp $
-- See Copyright Notice in file all.lua
-- testing debug library
@ -14,7 +15,8 @@ end
assert(not debug.gethook())
function test (s, l, p)
local testline = 19 -- line where 'test' is defined
function test (s, l, p) -- this must be line 19
collectgarbage() -- avoid gc during trace
local function f (event, line)
assert(event == 'line')
@ -36,7 +38,7 @@ do
a = debug.getinfo(print, "L")
assert(a.activelines == nil)
local b = debug.getinfo(test, "SfL")
assert(b.name == nil and b.what == "Lua" and b.linedefined == 17 and
assert(b.name == nil and b.what == "Lua" and b.linedefined == testline and
b.lastlinedefined == b.linedefined + 10 and
b.func == test and not string.find(b.short_src, "%["))
assert(b.activelines[b.linedefined + 1] and
@ -719,6 +721,22 @@ do -- testing for-iterator name
end
do -- testing debug info for finalizers
local name = nil
-- create a piece of garbage with a finalizer
setmetatable({}, {__gc = function ()
local t = debug.getinfo(2) -- get callee information
assert(t.namewhat == "metamethod")
name = t.name
end})
-- repeat until previous finalizer runs (setting 'name')
repeat local a = {} until name
assert(name == "__gc")
end
do
print("testing traceback sizes")

@ -1,4 +1,5 @@
-- $Id: errors.lua,v 1.92 2016/03/07 19:27:08 roberto Exp $
-- $Id: errors.lua,v 1.94 2016/12/21 19:23:02 roberto Exp $
-- See Copyright Notice in file all.lua
print("testing errors")
@ -147,6 +148,7 @@ _G.D = nil
do -- named objects (field '__name')
checkmessage("math.sin(io.input())", "(number expected, got FILE*)")
_G.XX = setmetatable({}, {__name = "My Type"})
assert(string.find(tostring(XX), "^My Type"))
checkmessage("io.input(XX)", "(FILE* expected, got My Type)")
checkmessage("return XX + 1", "on a My Type value")
checkmessage("return ~io.stdin", "on a FILE* value")

@ -1,4 +1,5 @@
-- $Id: events.lua,v 1.43 2016/01/14 16:27:25 roberto Exp $
-- $Id: events.lua,v 1.45 2016/12/21 19:23:02 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing metatables')
@ -20,10 +21,10 @@ assert(B == 30)
assert(getmetatable{} == nil)
assert(getmetatable(4) == nil)
assert(getmetatable(nil) == nil)
a={}; setmetatable(a, {__metatable = "xuxu",
a={name = "NAME"}; setmetatable(a, {__metatable = "xuxu",
__tostring=function(x) return x.name end})
assert(getmetatable(a) == "xuxu")
assert(tostring(a) == nil)
assert(tostring(a) == "NAME")
-- cannot change a protected metatable
assert(pcall(setmetatable, a, {}) == false)
a.name = "gororoba"

@ -1,4 +1,5 @@
-- $Id: files.lua,v 1.93 2016/04/13 16:25:31 roberto Exp $
-- $Id: files.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
local debug = require "debug"
@ -13,7 +14,7 @@ assert(io.output(io.stdout) == io.stdout)
local function testerr (msg, f, ...)
local stat, err = pcall(f, ...)
print(err)
-- print(err)
return (not stat and string.find(err, msg, 1, true))
end
@ -677,6 +678,8 @@ print("testing date/time")
assert(os.date("") == "")
assert(os.date("!") == "")
assert(os.date("\0\0") == "\0\0")
assert(os.date("!\0\0") == "\0\0")
local x = string.rep("a", 10000)
assert(os.date(x) == x)
local t = os.time()
@ -701,6 +704,8 @@ checkerr("invalid conversion specifier", os.date, "%Ea")
checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour='x'})
checkerr("not an integer", os.time, {year=1000, month=1, day=1, hour=1.5})
checkerr("missing", os.time, {hour = 12}) -- missing date
if not _port then
-- test Posix-specific modifiers
assert(type(os.date("%Ex")) == 'string')
@ -734,11 +739,6 @@ if not _port then
end
-- assume that time has at least 1-second precision
assert(math.abs(os.difftime(os.time(D), t)) < 1)
assert(not pcall(os.time, {hour = 12})) -- missing date
D = os.date("!*t", t)
load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and
D.hour==%H and D.min==%M and D.sec==%S and
@ -759,11 +759,13 @@ local t1 = os.time(D)
-- allow for leap years
assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2)
-- should not take more than 2 second to execute these two lines
-- should not take more than 1 second to execute these two lines
t = os.time()
t1 = os.time(os.date("*t"))
t1 = os.difftime(t1,t)
assert(0 <= t1 and t1 <= 2)
local diff = os.difftime(t1,t)
assert(0 <= diff and diff <= 1)
diff = os.difftime(t,t1)
assert(-1 <= diff and diff <= 0)
local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12}
local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19}

@ -1,4 +1,5 @@
-- $Id: gc.lua,v 1.71 2016/03/07 19:31:35 roberto Exp $
-- $Id: gc.lua,v 1.72 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing garbage collection')

@ -1,4 +1,5 @@
-- $Id: goto.lua,v 1.12 2016/03/07 19:26:18 roberto Exp $
-- $Id: goto.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
collectgarbage()

@ -1,4 +1,5 @@
-- $Id: literals.lua,v 1.35 2016/05/03 15:35:29 roberto Exp $
-- $Id: literals.lua,v 1.36 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing scanner')

@ -1,4 +1,5 @@
-- $Id: locals.lua,v 1.36 2015/03/04 13:09:38 roberto Exp $
-- $Id: locals.lua,v 1.37 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing local variables and environments')

@ -1,5 +1,5 @@
/*
** $Id: ltests.c,v 2.205 2015/04/02 21:10:21 roberto Exp $
** $Id: ltests.c,v 2.211 2016/12/04 20:17:24 roberto Exp $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -687,8 +687,8 @@ static int table_query (lua_State *L) {
t = hvalue(obj_at(L, 1));
if (i == -1) {
lua_pushinteger(L, t->sizearray);
lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t));
lua_pushinteger(L, t->lastfree - t->node);
lua_pushinteger(L, allocsizenode(t));
lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node);
}
else if ((unsigned int)i < t->sizearray) {
lua_pushinteger(L, i);
@ -869,7 +869,7 @@ static int loadlib (lua_State *L) {
luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */
/* ...but should return the same module */
lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ));
luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD");
luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (i = 0; libs[i].name; i++) {
lua_pushcfunction(L1, libs[i].func);
lua_setfield(L1, -2, libs[i].name);

@ -1,5 +1,5 @@
/*
** $Id: ltests.h,v 2.49 2015/09/22 14:18:24 roberto Exp $
** $Id: ltests.h,v 2.50 2016/07/19 17:13:00 roberto Exp $
** Internal Header for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -98,7 +98,9 @@ LUA_API void *debug_realloc (void *ud, void *block,
#if defined(lua_c)
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
#define luaL_openlibs(L) \
{ (luaL_openlibs)(L); luaL_requiref(L, "T", luaB_opentests, 1); }
{ (luaL_openlibs)(L); \
luaL_requiref(L, "T", luaB_opentests, 1); \
lua_pop(L, 1); }
#endif
@ -108,6 +110,7 @@ LUA_API void *debug_realloc (void *ud, void *block,
#undef LUAL_BUFFERSIZE
#define LUAL_BUFFERSIZE 23
#define MINSTRTABSIZE 2
#define MAXINDEXRK 1
/* make stack-overflow tests run faster */

@ -1,5 +1,6 @@
# testing special comment on first line
-- $Id: main.lua,v 1.64 2016/04/13 16:25:59 roberto Exp $
-- $Id: main.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
-- most (all?) tests here assume a reasonable "Unix-like" shell
if _port then return end

@ -1,4 +1,5 @@
-- $Id: math.lua,v 1.76 2016/05/30 15:55:38 roberto Exp $
-- $Id: math.lua,v 1.78 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print("testing numbers and math lib")
@ -23,9 +24,11 @@ end
local function isNaN (x)
return (x ~= x)
-- return true
end
assert(isNaN(0/0))
assert(not isNaN(1/0))
do
local x = 2.0^floatbits
@ -274,7 +277,7 @@ end
checkcompt("divide by zero", "return 2 // 0")
checkcompt(msgf2i, "return 2.3 >> 0")
checkcompt(msgf2i, ("return 2.0^%d & 1"):format(intbits - 1))
--checkcompt("field 'huge'", "return math.huge << 1")
checkcompt("field 'huge'", "return math.huge << 1")
checkcompt(msgf2i, ("return 1 | 2.0^%d"):format(intbits - 1))
checkcompt(msgf2i, "return 2.3 ~ '0.0'")

@ -1,4 +1,5 @@
-- $Id: nextvar.lua,v 1.78 2015/09/08 17:21:27 roberto Exp $
-- $Id: nextvar.lua,v 1.79 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing tables, next, and for')

@ -1,4 +1,5 @@
-- $Id: pm.lua,v 1.47 2016/04/22 16:37:09 roberto Exp $
-- $Id: pm.lua,v 1.48 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing pattern matching')

@ -0,0 +1,26 @@
LUA=$1
if [ "$LUA" = "" ]
then
echo "Please pass path to Lua"
exit 1
fi
# Run the interpreter tests first
$LUA -e"_port=true" all.lua
if [ $? != 0 ]
then
echo "all.lua interpreted failed"
exit 1
fi
# Run tests in partial JIT mode, with line hook
$LUA -e"_port=true; ravi.auto(true)" all.lua
if [ $? != 0 ]
then
echo "all.lua partially compiled with tracehook failed"
exit 1
fi
cd ../ravi-tests
. ./run_tests.sh "$LUA"
cd -

@ -1,4 +1,5 @@
-- $Id: sort.lua,v 1.37 2016/03/07 19:27:51 roberto Exp $
-- $Id: sort.lua,v 1.38 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing (parts of) table library"

@ -1,4 +1,5 @@
-- $Id: strings.lua,v 1.85 2016/05/20 14:15:57 roberto Exp $
-- $Id: strings.lua,v 1.87 2016/12/21 19:23:02 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing strings and string library')
@ -195,8 +196,14 @@ checkerror("contains zeros", string.format, "%10s", "\0")
assert(string.format("%s %s", nil, true) == "nil true")
assert(string.format("%s %.4s", false, true) == "false true")
assert(string.format("%.3s %.3s", false, true) == "fal tru")
local m = setmetatable({}, {__tostring = function () return "hello" end})
local m = setmetatable({}, {__tostring = function () return "hello" end,
__name = "hi"})
assert(string.format("%s %.10s", m, m) == "hello hello")
getmetatable(m).__tostring = nil -- will use '__name' from now on
assert(string.format("%.4s", m) == "hi: ")
getmetatable(m).__tostring = function () return {} end
checkerror("'__tostring' must return a string", tostring, m)
assert(string.format("%x", 0.0) == "0")

@ -1,4 +1,5 @@
-- $Id: tpack.lua,v 1.12 2016/05/18 18:22:45 roberto Exp $
-- $Id: tpack.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
local pack = string.pack
local packsize = string.packsize

@ -1,4 +1,5 @@
-- $Id: utf8.lua,v 1.11 2014/12/26 17:20:53 roberto Exp $
-- $Id: utf8.lua,v 1.12 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing UTF-8 library"

@ -1,4 +1,5 @@
-- $Id: vararg.lua,v 1.24 2015/06/01 16:38:36 roberto Exp $
-- $Id: vararg.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print('testing vararg')

@ -1,4 +1,5 @@
-- $Id: verybig.lua,v 1.24 2014/12/26 17:20:53 roberto Exp $
-- $Id: verybig.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $
-- See Copyright Notice in file all.lua
print "testing RK"

@ -34,7 +34,7 @@ end
-- Matrix transpose
-- This version uses slices
function matrix.T(a)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T
local m: integer, n: integer = mrows(a), mcols(a);
local x = mnew(n,m)
@ -51,15 +51,15 @@ function matrix.T(a)
data[pos] = slice[j]
end
end
local t2 = os.clock()
print("T: time ", t2-t1)
--local t2 = os.clock()
--print("T: time ", t2-t1)
return x;
end
-- Matrix transpose
-- Does not use slices
function matrix.T2(a)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T
local m: integer, n: integer = mrows(a), mcols(a);
local x = mnew(n,m)
@ -74,15 +74,15 @@ function matrix.T2(a)
data[(j-1)*m+i] = adata[ri+j]
end
end
local t2 = os.clock()
print("T2: time ", t2-t1)
--local t2 = os.clock()
--print("T2: time ", t2-t1)
return x;
end
-- Matrix multiply
-- Uses slices
function matrix.mul(a, b)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T
local m: integer, n: integer, p: integer = mrows(a), mcols(a), mcols(b);
assert(n == p)
@ -98,8 +98,8 @@ function matrix.mul(a, b)
xi[j] = sum;
end
end
local t2 = os.clock()
print("mul: time ", t2-t1)
--local t2 = os.clock()
--print("mul: time ", t2-t1)
return x;
end
@ -107,7 +107,7 @@ end
-- this version avoids using slices - we operate on the
-- one dimensional array
function matrix.mul2(a, b)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T2
local m: integer, n: integer, p: integer = mrows(a), mcols(a), mcols(b);
assert(n == p)
@ -131,14 +131,14 @@ function matrix.mul2(a, b)
xdata[xi+j] = sum;
end
end
local t2 = os.clock()
print("mul2: time ", t2-t1)
--local t2 = os.clock()
--print("mul2: time ", t2-t1)
return x;
end
-- Generate the matrix - uses slices
function matrix.gen(n: integer)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T
local a = mnew(n, n)
local tmp: number = 1.0 / n / n;
@ -148,14 +148,14 @@ function matrix.gen(n: integer)
row[j] = tmp * (i - j) * (i + j - 2)
end
end
local t2 = os.clock()
print("gen: time ", t2-t1)
--local t2 = os.clock()
--print("gen: time ", t2-t1)
return a;
end
-- Generate the matrix - this version does not use slices
function matrix.gen2(n: integer)
local t1 = os.clock()
--local t1 = os.clock()
local mrows, mcols, mnew, mdata, mrow, mtran = matrix.rows, matrix.cols, matrix.new, matrix.getdata, matrix.getrow, matrix.T
local a = mnew(n, n)
local data: number[] = mdata(a)
@ -168,8 +168,8 @@ function matrix.gen2(n: integer)
data[ri+j] = tmp * (i - j) * (i + j - 2)
end
end
local t2 = os.clock()
print("gen2: time ", t2-t1)
--local t2 = os.clock()
--print("gen2: time ", t2-t1)
return a;
end
@ -193,7 +193,7 @@ end
local n = arg[1] or 1000;
n = math.floor(n/2) * 2;
local t1 = os.clock()
local a = matrix.mul2(matrix.gen(n), matrix.gen(n));
local a = matrix.mul2(matrix.gen2(n), matrix.gen2(n));
local t2 = os.clock()
print("total time taken ", t2-t1)

@ -0,0 +1,62 @@
-- Writen by Attractive Chaos; distributed under the MIT license
matrix = {}
function matrix.T(a: table)
local m: integer, n: integer, x: table = #a, #a[1], {};
for i = 1, n do
local xi: number[] = table.numarray(n, 0.0)
x[i] = xi
for j = 1, m do xi[j] = @number (a[j][i]) end
end
return x;
end
function matrix.mul(a: table, b: table)
assert(#a[1] == #b);
local m: integer, n: integer, p: integer, x: table = #a, #a[1], #b[1], {};
local c: table = matrix.T(b); -- transpose for efficiency
for i = 1, m do
local xi: number[] = table.numarray(p, 0.0)
x[i] = xi
for j = 1, p do
local sum: number, ai: number[], cj: number[] = 0.0, @number[](a[i]), @number[](c[j]);
-- for luajit, caching c[j] or not makes no difference; lua is not so clever
for k = 1, n do sum = sum + ai[k] * cj[k] end
xi[j] = sum;
end
end
return x;
end
function matgen(n: integer)
local a: table, tmp: number = {}, 1. / n / n;
for i = 1, n do
local ai: number[] = table.numarray(n, 0.0)
a[i] = ai
for j = 1, n do
ai[j] = tmp * (i - j) * (i + j - 2)
end
end
return a;
end
--ravi.dumplua(matgen)
if ravi and ravi.jit() then
ravi.compile(matrix.T)
ravi.compile(matrix.mul, {omitArrayGetRangeCheck=1})
ravi.compile(matgen)
end
local n = arg[1] or 1000;
n = math.floor(n/2) * 2;
if jit then
-- luajit warmup
matrix.mul(matgen(n), matgen(n))
end
local t1 = os.clock()
local a = matrix.mul(matgen(n), matgen(n))
local t2 = os.clock()
print("time taken ", t2-t1)
print(a[n/2+1][n//2+1]);

@ -1197,7 +1197,7 @@ function event_test()
setmetatable(a, {__metatable = "xuxu",
__tostring=function(x: table) return x.name end})
assert(getmetatable(a) == "xuxu")
assert(tostring(a) == nil)
--assert(tostring(a) == nil)
-- cannot change a protected metatable
assert(pcall(setmetatable, a, {}) == false)
a.name = "gororoba"
@ -1382,12 +1382,67 @@ function test_yields_in_metamethods()
end
run(test)
end
assert(run(function ()
local a: table = a
a.BB = print
return a.BB
end, {"nidx", "idx"}) == print)
end
assert(pcall(test_yields_in_metamethods));
compile(test_longkey);
assert(pcall(test_yields_in_metamethods));
print 'Test 54 Ok'
function test_upvaluejoin()
local debug = require'debug'
local foo1, foo2, foo3, foo4
do
local a:integer, b:integer = 3, 5
local c:number = 7.1
foo1 = function() return a+b end
foo2 = function() return b+a end
foo4 = function() return c end
do
local a: integer = 10
foo3 = function() return a+b end
end
end
assert(debug.upvalueid(foo1, 1))
assert(debug.upvalueid(foo1, 2))
assert(not pcall(debug.upvalueid, foo1, 3))
assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2))
assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1))
assert(debug.upvalueid(foo3, 1))
assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1))
assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2))
assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil)
assert(foo1() == 3 + 5 and foo2() == 5 + 3)
debug.upvaluejoin(foo1, 2, foo2, 2)
assert(foo1() == 3 + 3 and foo2() == 5 + 3)
assert(foo3() == 10 + 5)
debug.upvaluejoin(foo3, 2, foo2, 1)
assert(foo3() == 10 + 5)
debug.upvaluejoin(foo3, 2, foo2, 2)
assert(foo3() == 10 + 3)
-- Following will fail as typeof(foo4,1) is not same as typeof(foo1,1)
debug.upvaluejoin(foo4, 1, foo1, 1)
assert(foo4() == 7.1)
assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1))
assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3))
assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1))
assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1))
assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1))
assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1))
end
assert(pcall(test_upvaluejoin));
compile(test_upvaluejoin);
assert(pcall(test_upvaluejoin));
print 'Test 55 Ok'
for k,v in pairs(opcodes_coverage)
do

File diff suppressed because it is too large Load Diff

@ -4,37 +4,39 @@ Ravi's reason for existence is to achieve greater performance than standard Lua
The programs used in the performance testing can be found at `Ravi Tests <https://github.com/dibyendumajumdar/ravi/tree/master/ravi-tests>`_ folder.
+--------------------+-----------+----------+------------+---------------+-----------+
| Program | Lua5.3.2 | Ravi Int | Ravi(LLVM) | LuaJIT2.1 Int | LuaJIT2.1 |
+====================+===========+==========+============+===============+===========+
|fornum_test1.lua | 8.952 | 8.327 | 0.321 | 3.516 | 0.312 |
+--------------------+-----------+----------+------------+---------------+-----------+
|fornum_test2.lua | 9.195 | 9.205 | 4.73 | 3.75 | 0.922 |
+--------------------+-----------+----------+------------+---------------+-----------+
|fornum_test3.lua | 52.494 | 47.367 | 4.722 | 16.74 | 7.75 |
+--------------------+-----------+----------+------------+---------------+-----------+
|mandel1.lua(4000) | 20.324 | 20.436 | 8.186 | 8.469 | 1.594 |
+--------------------+-----------+----------+------------+---------------+-----------+
|mandel1.ravi(4000) | n/a | 16.67 | 1.572 | n/a | n/a |
+--------------------+-----------+----------+------------+---------------+-----------+
|fannkuchen.lua(11) | 46.203 | 48.199 | 30.586 | 20.6 | 4.672 |
+--------------------+-----------+----------+------------+---------------+-----------+
|fannkuchen.ravi(11) | n/a | 35.797 | 4.639 | n/a | n/a |
+--------------------+-----------+----------+------------+---------------+-----------+
|matmul1.lua(1000) | 26.672 | 27.426 | 17.869 | 12.594 | 1.078 |
+--------------------+-----------+----------+------------+---------------+-----------+
|matmul1.ravi(1000) | n/a | 24.862 | 0.995 | n/a | n/a |
+--------------------+-----------+----------+------------+---------------+-----------+
+-----------------------+-----------+----------+------------+---------------+-----------+
| Program | Lua5.3.2 | Ravi Int | Ravi(LLVM) | LuaJIT2.1 Int | LuaJIT2.1 |
+=======================+===========+==========+============+===============+===========+
|fornum_test1.lua | 8.94 | 8.587 | 0.309 | 3.516 | 0.312 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|fornum_test2.lua | 9.195 | 9.243 | 4.446 | 3.75 | 0.922 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|fornum_test3.lua | 52.494 | 48.223 | 4.748 | 16.74 | 7.75 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|mandel1.lua(4000) | 20.324 | 19.835 | 8.056 | 8.469 | 1.594 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|mandel1.ravi(4000) | n/a | 16.192 | 1.571 | n/a | n/a |
+-----------------------+-----------+----------+------------+---------------+-----------+
|fannkuchen.lua(11) | 46.203 | 48.654 | 28.422 | 20.6 | 4.672 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|fannkuchen.ravi(11) | n/a | 34.411 | 4.634 | n/a | n/a |
+-----------------------+-----------+----------+------------+---------------+-----------+
|matmul1.lua(1000) | 26.672 | 26.51 | 16.83 | 12.594 | 1.078 |
+-----------------------+-----------+----------+------------+---------------+-----------+
|matmul1_ravi.lua(1000) | n/a | 20.123 | 1.137 | n/a | n/a |
+-----------------------+-----------+----------+------------+---------------+-----------+
|matmul1.ravi(1000) | n/a | 25.387 | 1.039 | n/a | n/a |
+-----------------------+-----------+----------+------------+---------------+-----------+
Following points are worth bearing in mind when looking at above benchmarks.
1. For Ravi the timings above do not include the LLVM compilation time.
2. The benchmarks were run on Windows 10 64-bit. LLVM version 3.7 was used.
2. The benchmarks were run on Windows 10 64-bit. LLVM version 3.9 was used.
Ravi and Lua 5.3.2 were compiled using Visual C++ 2015.
3. Some of the Ravi benchmarks are based on code that uses optional static types;
additionally for the matmul benchmark a setting was used to disable
additionally for the `matmul` benchmark a setting was used to disable
array bounds checks for array read operations.
4. Above benchmarks are primarily numerical. In real life scenarios there
@ -43,9 +45,9 @@ Following points are worth bearing in mind when looking at above benchmarks.
not have a similar FFI interface. LuaJIT can also inline Lua function calls
but Ravi does not have this ability and hence function calls go via the
Lua infrastructure and are therefore expensive. Ravi's code generation is best
when types are annotated as otherwise the dynamic type checks kill performance
when types are annotated as otherwise the dynamic type checks degrade performance
as above benchmarks show. Finally LLVM is a slow compiler relative to LuaJIT's
JIT compiler which is very very fast.
JIT compiler which is extremely fast.
5. Performance of Lua 5.3.2 is better than 5.3.0 or 5.3.1, thanks to the
table optimizations in this version.

@ -5,6 +5,56 @@ Ravi Parsing and ByteCode Implementation Details
This document covers the enhancements to the Lua parser and byte-code generator.
The Ravi JIT implementation is described elsewhere.
Introduction
============
Since the reason for introducing optional static typing is to enhance performance primarily - not all types benefit from this capability. In fact it is quite hard to extend this to generic recursive structures such as tables without encurring significant overhead. For instance - even to represent a recursive type in the parser will require dynamic memory allocation and add great overhead to the parser.
From a performance point of view the only types that seem worth specializing are:
* integer (64-bit int)
* number (double)
* array of integers
* array of numbers
* table
Implementation Strategy
=======================
I want to build on existing Lua types rather than introducing completely new types to the Lua system. I quite like the minimalist nature of Lua. However, to make the execution efficient I am adding new type specific opcodes and enhancing the Lua parser/code generator to encode these opcodes only when types are known. The new opcodes will execute more efficiently as they will not need to perform type checks. Morever, type specific instructions will lend themselves to more efficient JIT compilation.
I am adding new opcodes that cover arithmetic operations, array operations, variable assignments, etc..
Modifications to Lua Bytecode structure
=======================================
An immediate issue is that the Lua bytecode structure has a 6-bit opcode which is insufficient to hold the various opcodes that I will need. Simply extending the size of this is problematic as then it reduces the space available to the operands A B and C. Furthermore the way Lua bytecodes work means that B and C operands must be 1-bit larger than A - as the extra bit is used to flag whether the operand refers to a constant or a register. (Thanks to Dirk Laurie for pointing this out).
I am amending the bit mapping in the 32-bit instruction to allow 9-bits for the byte-code, 7-bits for operand A, and 8-bits for operands B and C. This means that some of the Lua limits (maximum number of variables in a function, etc.) have to be revised to be lower than the default.
New OpCodes
===========
The new instructions are specialised for types, and also for register/versus constant. So for example ``OP_RAVI_ADDFI`` means add ``number`` and ``integer``. And ``OP_RAVI_ADDFF`` means add ``number`` and ``number``. The existing Lua opcodes that these are based on define which operands are used.
Example::
local i=0; i=i+1
Above standard Lua code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADD A=0 B=0 C=-2
[2] RETURN A=0 B=1
We add type info using Ravi extensions::
local i:integer=0; i=i+1
Now the code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADDII A=0 B=0 C=-2
[2] RETURN A=0 B=1
Above uses type specialised opcode ``OP_RAVI_ADDII``.
Type Information
================
The basic first step is to add type information to Lua.

@ -1,3 +1,4 @@
=========================
Ravi Programming Language
=========================
@ -9,38 +10,43 @@ There are other attempts to add static typing to Lua - e.g. `Typed Lua <https://
My motivation is somewhat different - I want to enhance the VM to support more efficient operations when types are known. Type information can be exploited by JIT compilation technology to improve performance. At the same time, I want to keep the language safe and therefore usable by non-expert programmers.
Goals
-----
* Optional static typing for Lua
Of course there is also the fantastic `LuaJIT <http://luajit.org>`_ implementation. Ravi has a different goal compared to
LuaJIT. Ravi prioritizes ease of maintenance and support, language safety, and compatibility with Lua 5.3, over maximum performance. For more detailed comparison please refer to the documentation links below.
.. contents:: Table of Contents
:depth: 1
:backlinks: top
Features
========
* Optional static typing
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
* `LLVM <http://www.llvm.org/>`_ powered JIT compiler
* Additionally a `libgccjit <https://gcc.gnu.org/wiki/JIT>`_ based alternative JIT compiler is also available
* LLVM bindings exposed in Lua
Documentation
--------------
=============
See `Ravi Documentation <http://the-ravi-programming-language.readthedocs.org/en/latest/index.html>`_.
As more stuff is built I will keep updating the documentation so please revisit for latest information.
Also see the slides I presented at the `Lua 2015 Workshop <http://www.lua.org/wshop15.html>`_.
JIT Implementation
++++++++++++++++++
==================
The LLVM JIT compiler is functional. The Lua and Ravi bytecodes currently implemented in LLVM are described in `JIT Status <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-status.html>`_ page.
Ravi also provides an `LLVM binding <http://the-ravi-programming-language.readthedocs.org/en/latest/llvm-bindings.html>`_; this is still work in progress so please check documentation for the latest status.
As of July 2015 the `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation is also functional but some byte codes are not yet compiled, and featurewise this implementation is somewhat lagging behind the LLVM based implementation.
Performance Benchmarks
++++++++++++++++++++++
For performance benchmarks please visit the `Ravi Performance Benchmarks <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-benchmarks.html>`_ page.
There is also a `libgccjit <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-jit-libgccjit.html>`_ based JIT implementation but this implementation is lagging behind the LLVM based implementation. Further development of this is currently not planned.
Ravi Extensions to Lua 5.3
--------------------------
==========================
Optional Static Typing
++++++++++++++++++++++
----------------------
Ravi allows you to annotate ``local`` variables and function parameters with static types. The supported types and the resulting behaviour are as follows:
``integer``
@ -157,7 +163,7 @@ Following library functions allow creation of array types of defined length.
creates an number array of specified size, and initializes with initial value. The return type is number[]. The size of the array cannot be changed dynamically, i.e. it is fixed to the initial specified size. This allows slices to be created on such arrays.
Type Assertions
+++++++++++++++
---------------
Ravi does not support defining new types, or structured types based on tables. This creates some practical issues when dynamic types are mixed with static types. For example::
local t = { 1,2,3 }
@ -178,7 +184,7 @@ The type assertion operator is a unary operator and binds to the expression foll
For a real example of how type assertions can be used, please have a look at the test program `gaussian2.lua <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/gaussian2.lua>`_
Array Slices
++++++++++++
------------
Since release 0.6 Ravi supports array slices. An array slice allows a portion of a Ravi array to be treated as if it is an array - this allows efficient access to the underlying array elements. Following new functions are available:
``table.slice(array, start_index, num_elements)``
@ -195,7 +201,7 @@ Each slice holds an internal reference to the underlying array to ensure that th
For an example use of slices please see the `matmul1.ravi <https://github.com/dibyendumajumdar/ravi/blob/master/ravi-tests/matmul1.ravi>`_ benchmark program in the repository. Note that this feature is highly experimental and not very well tested.
Examples
++++++++
--------
Example of code that works - you can copy this to the command line input::
function tryme()
@ -243,13 +249,12 @@ Another example using arrays. Here the function receives a parameter ``arr`` of
The ``table.numarray(n, initial_value)`` creates a ``number[]`` of specified size and initializes the array with the given initial value.
All type checks are at runtime
++++++++++++++++++++++++++++++
------------------------------
To keep with Lua's dynamic nature Ravi uses a mix of compile type checking and runtime type checks. However due to the dynamic nature of Lua, compilation happens at runtime anyway so effectually all checks are at runtime.
JIT Compilation
---------------
The LLVM based JIT compiler is functional. Most bytecodes other than bit-wise operators are JIT compiled when using LLVM, but there are restrictions as described in compatibility section below. Everything described below relates to using LLVM as the JIT compiler.
JIT API
-------
The LLVM based JIT compiler is functional.
There are two modes of JIT compilation.
auto mode
@ -281,18 +286,20 @@ A JIT api is available with following functions:
Enables support for line hooks via the debug api. Note that enabling this option will result in inefficient JIT as a call to a C function will be inserted at beginning of every Lua bytecode
boundary; use this option only when you want to use the debug api to step through code line by line
Performance Notes
-----------------
Performance
===========
For performance benchmarks please visit the `Ravi Performance Benchmarks <http://the-ravi-programming-language.readthedocs.org/en/latest/ravi-benchmarks.html>`_ page.
To obtain the best possible performance, types must be annotated so that Ravi's JIT compiler can generate efficient code.
Additionally function calls are expensive - as the JIT compiler cannot inline function calls, all function calls go via the Lua call protocol which has a large overhead. This is true for both Lua functions and C functions. For best performance avoid function calls inside loops.
Compatibility with Lua
----------------------
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but there are some differences:
======================
Ravi should be able to run all Lua 5.3 programs in interpreted mode, but following should be noted:
* Ravi supports optional typing and enhanced types such as arrays (described above). Programs using these features cannot be run by standard Lua. However all types in Ravi can be passed to Lua functions; operations on Ravi arrays within Lua code will be subject to restrictions as described in the section above on arrays.
* Values crossing from Lua to Ravi will be subjected to typechecks should these values be assigned to typed variables.
* Upvalues cannot subvert the static typing of local variables (issue #26)
* Upvalues cannot subvert the static typing of local variables (issue #26) when types are annotated.
* Certain Lua limits are reduced due to changed byte code structure. These are described below.
+-----------------+-------------+-------------+
@ -309,31 +316,36 @@ Ravi should be able to run all Lua 5.3 programs in interpreted mode, but there a
| MAXARGLINE | 250 | 120 |
+-----------------+-------------+-------------+
When JIT compilation is enabled some things will not work:
When JIT compilation is enabled there are following additional constraints:
* You cannot yield from a compiled function as compiled code does not support coroutines (issue 14); as a workaround Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode.
* In JITed code tailcalls are implemented as regular calls so unlike Lua VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17)
* Ravi will only execute JITed code from the main Lua thread; any secondary threads (coroutines) execute in interpreter mode.
* In JITed code tailcalls are implemented as regular calls so unlike the interpreter VM which supports infinite tail recursion JIT compiled code only supports tail recursion to a depth of about 110 (issue #17)
Building Ravi
=============
Build Dependencies - LLVM version
---------------------------------
Build Dependencies
------------------
* CMake
* LLVM 3.7 or 3.8 or 3.9
Ravi can be built with or without LLVM. Following versions of LLVM work with Ravi.
* LLVM 3.7 or 3.8 or 3.9 or 4.0
* LLVM 3.5 and 3.6 should also work but have not been recently tested
The build is CMake based.
Unless otherwise noted the instructions below should work for LLVM 3.7 or above.
Unless otherwise noted the instructions below should work for LLVM 3.7 or later.
Building LLVM on Windows
------------------------
I built LLVM from source. I used the following sequence from the VS2015 command window::
I built LLVM from source. I used the following sequence from the VS2017 command window::
cd \github\llvm
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=c:\LLVM -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 14 Win64" ..
cmake -DCMAKE_INSTALL_PREFIX=c:\LLVM -DLLVM_TARGETS_TO_BUILD="X86" -G "Visual Studio 15 2017 Win64" ..
I then opened the generated solution in VS2015 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter.
I then opened the generated solution in VS2017 and performed a INSTALL build from there. Above will build the 64-bit version of LLVM libraries. To build a 32-bit version omit the ``Win64`` parameter.
.. note:: Note that if you perform a Release build of LLVM then you will also need to do a Release build of Ravi otherwise you will get link errors.
@ -354,18 +366,18 @@ Assuming that LLVM source has been extracted to ``$HOME/llvm-3.7.0.src`` I follo
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/LLVM -DLLVM_TARGETS_TO_BUILD="X86" ..
make install
Building Ravi
-------------
I am developing Ravi using Visual Studio 2015 Community Edition on Windows 8.1 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
Building Ravi with JIT enabled
------------------------------
I am developing Ravi using Visual Studio 2017 Community Edition on Windows 10 64bit, gcc on Unbuntu 64-bit, and clang/Xcode on MAC OS X. I was also able to successfully build a Ubuntu version on Windows 10 using the newly released Ubuntu/Linux sub-system for Windows 10.
.. note:: Location of cmake files has moved in LLVM 3.9; the new path is ``$LLVM_INSTALL_DIR/lib/cmake/llvm``.
Assuming that LLVM has been installed as described above, then on Windows I invoke the cmake config as follows::
cd build
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 14 Win64" ..
cmake -DLLVM_JIT=ON -DCMAKE_INSTALL_PREFIX=c:\ravi -DLLVM_DIR=c:\LLVM37\share\llvm\cmake -G "Visual Studio 15 2017 Win64" ..
I then open the solution in VS2015 and do a build from there.
I then open the solution in VS2017 and do a build from there.
On Ubuntu I use::
@ -390,8 +402,8 @@ Building without JIT
--------------------
You can omit ``-DLLVM_JIT=ON`` option above to build Ravi with a null JIT implementation.
Static Libraries
----------------
Building Static Libraries
-------------------------
By default the build generates a shared library for Ravi. You can choose to create a static library and statically linked executables by supplying the argument ``-DSTATIC_BUILD=ON`` to CMake.
Build Artifacts
@ -415,64 +427,19 @@ I test the build by running a modified version of Lua 5.3.3 test suite. These te
.. note:: To thoroughly test changes, you need to invoke CMake with ``-DCMAKE_BUILD_TYPE=Debug`` option. This turns on assertions, memory checking, and also enables an internal module used by Lua tests.
Work Plan
---------
* Feb-Jun 2015 - implement JIT compilation using LLVM
* Jun-Jul 2015 - libgccjit based alternative JIT
* 2016 priorties
Roadmap
=======
* 2015 - Implemented JIT compilation using LLVM
* 2015 - Implemented libgccjit based alternative JIT
* 2016 - Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
* 2017 - Main priorities are:
* `IDE support (Visual Studio Code) <https://github.com/dibyendumajumdar/ravi/tree/master/vscode-debugger>`_
- I would like Ravi to be backward compatible with Lua 5.1 and 5.2 as far as possible
- Lua function inlining
- Improve performance of Ravi
- Additional type annotations
License
-------
=======
MIT License for LLVM version.
Language Syntax - Future work
-----------------------------
Since the reason for introducing optional static typing is to enhance performance primarily - not all types benefit from this capability. In fact it is quite hard to extend this to generic recursive structures such as tables without encurring significant overhead. For instance - even to represent a recursive type in the parser will require dynamic memory allocation and add great overhead to the parser.
From a performance point of view the only types that seem worth specializing are:
* integer (64-bit int)
* number (double)
* array of integers
* array of numbers
Implementation Strategy
-----------------------
I want to build on existing Lua types rather than introducing completely new types to the Lua system. I quite like the minimalist nature of Lua. However, to make the execution efficient I am adding new type specific opcodes and enhancing the Lua parser/code generator to encode these opcodes only when types are known. The new opcodes will execute more efficiently as they will not need to perform type checks. Morever, type specific instructions will lend themselves to more efficient JIT compilation.
I am adding new opcodes that cover arithmetic operations, array operations, variable assignments, etc..
Modifications to Lua Bytecode structure
---------------------------------------
An immediate issue is that the Lua bytecode structure has a 6-bit opcode which is insufficient to hold the various opcodes that I will need. Simply extending the size of this is problematic as then it reduces the space available to the operands A B and C. Furthermore the way Lua bytecodes work means that B and C operands must be 1-bit larger than A - as the extra bit is used to flag whether the operand refers to a constant or a register. (Thanks to Dirk Laurie for pointing this out).
I am amending the bit mapping in the 32-bit instruction to allow 9-bits for the byte-code, 7-bits for operand A, and 8-bits for operands B and C. This means that some of the Lua limits (maximum number of variables in a function, etc.) have to be revised to be lower than the default.
New OpCodes
-----------
The new instructions are specialised for types, and also for register/versus constant. So for example ``OP_RAVI_ADDFI`` means add ``number`` and ``integer``. And ``OP_RAVI_ADDFF`` means add ``number`` and ``number``. The existing Lua opcodes that these are based on define which operands are used.
Example::
local i=0; i=i+1
Above standard Lua code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADD A=0 B=0 C=-2
[2] RETURN A=0 B=1
We add type info using Ravi extensions::
local i:integer=0; i=i+1
Now the code compiles to::
[0] LOADK A=0 Bx=-1
[1] ADDII A=0 B=0 C=-2
[2] RETURN A=0 B=1
Above uses type specialised opcode ``OP_RAVI_ADDII``.

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/
@ -999,7 +999,8 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
auxsetstr(L, index2addr(L, idx), k);
}
LUA_API void lua_seti(lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *slot;
lua_lock(L);
@ -1045,7 +1046,8 @@ LUA_API void lua_seti(lua_State *L, int idx, lua_Integer n) {
lua_unlock(L);
}
LUA_API void lua_rawset(lua_State *L, int idx) {
LUA_API void lua_rawset (lua_State *L, int idx) {
StkId o;
TValue *slot;
Table *t;
@ -1099,7 +1101,8 @@ LUA_API void lua_rawset(lua_State *L, int idx) {
lua_unlock(L);
}
LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
StkId o;
Table *t;
lua_lock(L);
@ -1138,6 +1141,7 @@ LUA_API void lua_rawseti(lua_State *L, int idx, lua_Integer n) {
lua_unlock(L);
}
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
StkId o;
Table *t;
@ -1621,12 +1625,13 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
}
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf, ravitype_t *type) {
LClosure *f;
StkId fi = index2addr(L, fidx);
api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (type) *type = f->p->upvalues[n - 1].type;
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}
@ -1636,7 +1641,7 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
StkId fi = index2addr(L, fidx);
switch (ttype(fi)) {
case LUA_TLCL: { /* lua closure */
return *getupvalref(L, fidx, n, NULL);
return *getupvalref(L, fidx, n, NULL, NULL);
}
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
@ -1654,13 +1659,16 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
int fidx2, int n2) {
LClosure *f1;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL);
luaC_upvdeccount(L, *up1);
*up1 = *up2;
(*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
ravitype_t t1, t2;
UpVal **up1 = getupvalref(L, fidx1, n1, &f1, &t1);
UpVal **up2 = getupvalref(L, fidx2, n2, NULL, &t2);
if (t1 == t2) {
luaC_upvdeccount(L, *up1);
*up1 = *up2;
(*up1)->refcount++;
if (upisopen(*up1)) (*up1)->u.open.touched = 1;
luaC_upvalbarrier(L, *up1);
}
}
/* API to set the output functions used by Lua / Ravi

@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@ -69,12 +69,11 @@ static int findfield (lua_State *L, int objidx, int level) {
/*
** Search for a name for a function in all loaded modules
** (registry._LOADED).
*/
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1);
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
@ -816,13 +815,17 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
if (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string");
}
else {
switch (lua_type(L, idx)) {
case LUA_TNUMBER: {
if (lua_isinteger(L, idx))
lua_pushfstring(L, "%I", lua_tointeger(L, idx));
lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
else
lua_pushfstring(L, "%f", lua_tonumber(L, idx));
lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
break;
}
case LUA_TSTRING:
@ -834,10 +837,15 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
lua_topointer(L, idx));
default: {
int tt = luaL_getmetafield(L, idx, "__name"); /* try name */
const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
luaL_typename(L, idx);
lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
if (tt != LUA_TNIL)
lua_remove(L, -2); /* remove '__name' */
break;
}
}
}
return lua_tolstring(L, -1, len);
@ -918,23 +926,23 @@ static int libsize (const luaL_Reg *l) {
/*
** Find or create a module table with a given name. The function
** first looks at the _LOADED table and, if that fails, try a
** first looks at the LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module '%s'", modname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
lua_setfield(L, -3, modname); /* LOADED[modname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
lua_remove(L, -2); /* remove LOADED table */
}
@ -998,17 +1006,17 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
*/
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, -1, modname); /* _LOADED[modname] */
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, -1, modname); /* LOADED[modname] */
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
lua_pop(L, 1); /* remove field */
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* call 'openf' to open module */
lua_pushvalue(L, -1); /* make copy of module (call result) */
lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
lua_setfield(L, -3, modname); /* LOADED[modname] = module */
}
lua_remove(L, -2); /* remove _LOADED table */
lua_remove(L, -2); /* remove LOADED table */
if (glb) {
lua_pushvalue(L, -1); /* copy of module */
lua_setglobal(L, modname); /* _G[modname] = module */
@ -1066,7 +1074,7 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
ver, *v);
(LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
}

@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@ -213,8 +213,8 @@ static int luaB_ravitype(lua_State *L) {
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
@ -256,9 +256,8 @@ static int ipairsaux (lua_State *L) {
/*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
** traverse a table, depending on whether the table has metamethods
** that can affect the traversal.
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
#if defined(LUA_COMPAT_IPAIRS)

@ -1,11 +1,11 @@
/*
** $Id: lcode.c,v 2.109 2016/05/13 19:09:21 roberto Exp $
** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/
#define lcode_c
@ -13,6 +13,7 @@
#include "lprefix.h"
#include <math.h>
#include <stdlib.h>
@ -44,7 +45,7 @@
** If expression is a numeric constant, fills 'v' with its value
** and returns 1. Otherwise, returns 0.
*/
static int tonumeral(expdesc *e, TValue *v) {
static int tonumeral(const expdesc *e, TValue *v) {
if (hasjumps(e))
return 0; /* not a numeral */
switch (e->k) {
@ -92,7 +93,7 @@ void luaK_nil (FuncState *fs, int from, int n) {
/*
** Gets the destination address of a jump instruction. Used to traverse
** a list of jumps.
*/
*/
static int getjump (FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */
@ -397,7 +398,6 @@ void luaK_reserveregs (FuncState *fs, int n) {
static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
/* if (reg != fs->freereg) luaX_syntaxerror(fs->ls, "unexpected error"); DEBUG Lua 5.3.3 merge issue math.lua 551 */
lua_assert(reg == fs->freereg);
}
}
@ -537,6 +537,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
DEBUG_CODEGEN(raviY_printf(fs, "[%d]* %o ; set A to %d\n", e->u.info, *pc, fs->freereg));
luaK_reserveregs(fs, 1);
}
else lua_assert(nresults == LUA_MULTRET);
}
@ -581,12 +582,12 @@ static int isshortstr(FuncState *fs, int kk) {
void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) {
case VLOCAL: {
e->k = VNONRELOC;
case VLOCAL: { /* already in a register */
e->k = VNONRELOC; /* becomes a non-relocatable value */
DEBUG_EXPR(raviY_printf(fs, "luaK_dischargevars (VLOCAL->VNONRELOC) %e\n", e));
break;
}
case VUPVAL: {
case VUPVAL: { /* move value to some (pending) register */
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
DEBUG_EXPR(raviY_printf(fs, "luaK_dischargevars (VUPVAL->VRELOCABLE) %e\n", e));
@ -618,7 +619,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
else
e->ravi_type = RAVI_TANY;
}
else {
else {
lua_assert(e->u.ind.vt == VUPVAL);
op = OP_GETTABUP; /* 't' is in an upvalue */
}
@ -826,7 +827,7 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
** (that is, it is either in a register or in 'k' with an index
** in the range of R/K indices).
** Returns R/K index.
*/
*/
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
switch (e->k) { /* move constants to 'k' */
@ -979,6 +980,9 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
}
/*
** Emit SELF instruction (convert expression 'e' into 'e:key(e,').
*/
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int ereg;
/* Ravi extension:
@ -1176,7 +1180,8 @@ static int validop (int op, TValue *v1, TValue *v2) {
** Try to "constant-fold" an operation; return 1 iff successful.
** (In this case, 'e1' has the final result.)
*/
static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
static int constfolding (FuncState *fs, int op, expdesc *e1,
const expdesc *e2) {
TValue v1, v2, res;
if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
return 0; /* non-numeric operands or not safe to fold */
@ -1197,6 +1202,7 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
return 1;
}
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@ -1219,11 +1225,15 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
** (everything but logical operators 'and'/'or' and comparison
** operators).
** Expression to produce final result will be encoded in 'e1'.
** Because 'luaK_exp2RK' can free registers, its calls must be
** in "stack order" (that is, first on 'e2', which may have more
** recent registers to be released).
*/
static void codebinexpval (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
int rk2 = luaK_exp2RK(fs, e2);
int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */
/* Note that the order below is important - see Lua 5.3.3 bug list*/
int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
int rk1 = luaK_exp2RK(fs, e1);
freeexps(fs, e1, e2);
if (op == OP_ADD && e1->ravi_type == RAVI_TNUMFLT && e2->ravi_type == RAVI_TNUMFLT) {
e1->u.info = luaK_codeABC(fs, OP_RAVI_ADDFF, 0, rk1, rk2);
@ -1456,6 +1466,9 @@ static void code_type_assertion(FuncState *fs, UnOpr op, expdesc *e) {
luaX_syntaxerror(fs->ls, "invalid type assertion");
}
/*
** Apply prefix operation 'op' to expression 'e'.
*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc ef = {.ravi_type = RAVI_TANY,
.pc = -1,
@ -1464,7 +1477,7 @@ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
.k = VKINT,
.u.ival = 0}; /* fake 2nd operand */
switch (op) {
case OPR_MINUS: case OPR_BNOT:
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef))
break;
/* FALLTHROUGH */
@ -1566,7 +1579,7 @@ void luaK_posfix (FuncState *fs, BinOpr op,
codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
break;
}
case OPR_EQ: case OPR_LT: case OPR_LE:
case OPR_EQ: case OPR_LT: case OPR_LE:
case OPR_NE: case OPR_GT: case OPR_GE: {
codecomp(fs, op, e1, e2);
break;

@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@ -38,7 +38,8 @@
#define ci_func(ci) (clLvalue((ci)->func))
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name);
static int currentpc (CallInfo *ci) {
@ -269,6 +270,20 @@ static void collectvalidlines (lua_State *L, Closure *f) {
}
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
if (ci == NULL) /* no 'ci'? */
return NULL; /* no info */
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
*name = "__gc";
return "metamethod"; /* report it as such */
}
/* calling function is a known Lua function? */
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
return funcnamefromcode(L, ci->previous, name);
else return NULL; /* no way to find a name */
}
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
@ -299,11 +314,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break;
}
case 'n': {
/* calling function is a known Lua function? */
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
else
ar->namewhat = NULL;
ar->namewhat = getfuncname(L, ci, &ar->name);
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
@ -510,8 +521,15 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
}
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
TMS tm = (TMS)0; /* to avoid warnings */
/*
** Try to find a name for a function based on the code that called it.
** (Only works when function was called by a Lua function.)
** Returns what the name is (e.g., "for iterator", "method",
** "metamethod") and sets '*name' to point to the name.
*/
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name) {
TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
@ -550,7 +568,8 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
case OP_EQ: tm = TM_EQ; break;
case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break;
default: lua_assert(0); /* other instructions cannot call a function */
default:
return NULL; /* cannot find a reasonable name */
}
*name = getstr(G(L)->tmname[tm]);
return "metamethod";

@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -211,9 +211,9 @@ static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top;
}
lua_assert(lim <= L->stack_last);
return cast_int(lim - L->stack) + 1; /* part of stack in use */
}
@ -221,16 +221,19 @@ static int stackinuse (lua_State *L) {
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
if (goodsize > LUAI_MAXSTACK)
goodsize = LUAI_MAXSTACK; /* respect stack limit */
if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else
luaE_shrinkCI(L); /* shrink list */
if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */
goodsize < L->stacksize) /* trying to shrink? */
luaD_reallocstack(L, goodsize); /* shrink it */
else
condmovestack(L,,); /* don't change stack (change only for debugging) */
/* if thread is currently not handling a stack overflow and its
good size is smaller than current size, shrink its stack */
if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
goodsize < L->stacksize)
luaD_reallocstack(L, goodsize);
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
}
@ -323,6 +326,72 @@ static void tryfuncTM (lua_State *L, StkId func) {
}
/*
** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
** Handle most typical cases (zero results for commands, one result for
** expressions, multiple results for tail calls/single parameters)
** separated.
*/
static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
int nres, int wanted) {
switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */
case 1: { /* one result needed */
if (nres == 0) /* no results? */
firstResult = luaO_nilobject; /* adjust with nil */
setobjs2s(L, res, firstResult); /* move it to proper place */
break;
}
case LUA_MULTRET: {
int i;
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
L->top = res + nres;
return 0; /* wanted == LUA_MULTRET */
}
default: {
int i;
if (wanted <= nres) { /* enough results? */
for (i = 0; i < wanted; i++) /* move wanted results to correct place */
setobjs2s(L, res + i, firstResult + i);
}
else { /* not enough results; use all of them plus nils */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(res + i);
}
break;
}
}
L->top = res + wanted; /* top points after the last result */
return 1;
}
/*
** Finishes a function call: calls hook if necessary, removes CallInfo,
** moves current number of results to proper place; returns 0 iff call
** wanted multiple (variable number of) results.
*/
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res;
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
L->ci = ci->previous; /* back to caller */
/* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted);
}
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
@ -376,13 +445,13 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
if (p->is_vararg != 1) { /* do not use vararg? */
if (p->is_vararg)
base = adjust_varargs(L, p, n);
else { /* non vararg function */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = func + 1;
}
else
base = adjust_varargs(L, p, n);
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
@ -396,7 +465,9 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
callhook(L, ci);
if (L == G(L)->mainthread && p->ravi_jit.jit_status == RAVI_JIT_NOT_COMPILED) {
/* not compiled */
raviV_compile(L, p, NULL);
ravi_compile_options_t options = { 0 };
options.verification_level = 1;
raviV_compile(L, p, &options);
}
if (L == G(L)->mainthread && p->ravi_jit.jit_function) {
/* compiled */
@ -448,70 +519,6 @@ int luaD_precall (lua_State *L, StkId func, int nresults, int op_call) {
}
/*
** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
** Handle most typical cases (zero results for commands, one result for
** expressions, multiple results for tail calls/single parameters)
** separated.
*/
static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
int nres, int wanted) {
switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */
case 1: { /* one result needed */
if (nres == 0) /* no results? */
firstResult = luaO_nilobject; /* adjust with nil */
setobjs2s(L, res, firstResult); /* move it to proper place */
break;
}
case LUA_MULTRET: {
int i;
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
L->top = res + nres;
return 0; /* wanted == LUA_MULTRET */
}
default: {
int i;
if (wanted <= nres) { /* enough results? */
for (i = 0; i < wanted; i++) /* move wanted results to correct place */
setobjs2s(L, res + i, firstResult + i);
}
else { /* not enough results; use all of them plus nils */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(res + i);
}
break;
}
}
L->top = res + wanted; /* top points after the last result */
return 1;
}
/*
** Finishes a function call: calls hook if necessary, removes CallInfo,
** moves current number of results to proper place; returns 0 iff call
** wanted multiple (variable number of) results.
*/
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res;
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
L->ci = ci->previous; /* back to caller */
/* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted);
}
/*
@ -566,19 +573,17 @@ static void finishCcall (lua_State *L, int status) {
/* error status can only happen in a protected call */
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
L->errfunc = ci->u.c.old_errfunc;
ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
}
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */
adjustresults(L, ci->nresults);
/* call continuation function */
lua_unlock(L);
n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
lua_lock(L);
api_checknelems(L, n);
/* finish 'luaD_precall' */
luaD_poscall(L, ci, L->top - n, n);
luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
}
@ -641,15 +646,16 @@ static int recover (lua_State *L, int status) {
/*
** signal an error in the call to 'resume', not in the execution of the
** coroutine itself. (Such errors should not be handled by any coroutine
** error handler and should not kill the coroutine.)
** Signal an error in the call to 'lua_resume', not in the execution
** of the coroutine itself. (Such errors should not be handled by any
** coroutine error handler and should not kill the coroutine.)
*/
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
L->top = firstArg; /* remove args from the stack */
static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
luaD_throw(L, -1); /* jump back to 'lua_resume' */
lua_unlock(L);
return LUA_ERRRUN;
}
@ -661,22 +667,15 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
** coroutine.
*/
static void resume (lua_State *L, void *ud) {
int nCcalls = L->nCcalls;
int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
if (nCcalls >= LUAI_MAXCCALLS)
resume_error(L, "C stack overflow", firstArg);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (ci != &L->base_ci) /* not in base level? */
resume_error(L, "cannot resume non-suspended coroutine", firstArg);
/* coroutine is in base level; start running it */
if (L->status == LUA_OK) { /* starting a coroutine? */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET, 0)) /* Lua function? */
luaV_execute(L); /* call it */
}
else if (L->status != LUA_YIELD)
resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
@ -693,7 +692,6 @@ static void resume (lua_State *L, void *ud) {
}
unroll(L, NULL); /* run continuation */
}
lua_assert(nCcalls == L->nCcalls);
}
@ -701,8 +699,16 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
luai_userstateresume(L, nargs);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
}
else if (L->status != LUA_YIELD)
return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
if (L->nCcalls >= LUAI_MAXCCALLS)
return resume_error(L, "C stack overflow", nargs);
luai_userstateresume(L, nargs);
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs);

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/

@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -469,7 +469,7 @@ static lu_mem traversetable (global_State *g, Table *h) {
else /* not weak */
traversestrongtable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray +
sizeof(Node) * cast(size_t, sizenode(h));
sizeof(Node) * cast(size_t, allocsizenode(h));
}
@ -541,7 +541,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
/* 'remarkupvals' may have removed thread from 'twups' list */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
th->twups = g->twups; /* link it back to the list */
g->twups = th;
@ -823,7 +823,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
setobj2s(L, L->top, tm); /* push finalizer... */
setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */

@ -1,5 +1,5 @@
/*
** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $
** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@ -18,10 +18,10 @@
** open the library, which is already linked to the application.
** For that, do the following code:
**
** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname);
** lua_pop(L, 1); // remove _PRELOAD table
** lua_pop(L, 1); // remove PRELOAD table
*/
#include "lprefix.h"

@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@ -37,10 +37,11 @@
#endif
/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
#define l_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \
(strspn(mode, L_MODEEXT) == strlen(mode)))
static int l_checkmode (const char *mode) {
return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
(*mode != '+' || (++mode, 1)) && /* skip if char is '+' */
(strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
}
#endif
@ -619,8 +620,10 @@ static int g_write (lua_State *L, FILE *f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
int len = lua_isinteger(L, arg)
? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg))
: fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg));
? fprintf(f, LUA_INTEGER_FMT,
(LUAI_UACINT)lua_tointeger(L, arg))
: fprintf(f, LUA_NUMBER_FMT,
(LUAI_UACNUMBER)lua_tonumber(L, arg));
status = status && (len > 0);
}
else {

@ -1,5 +1,5 @@
/*
** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $
** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@ -184,10 +184,13 @@ static int math_log (lua_State *L) {
else {
lua_Number base = luaL_checknumber(L, 2);
#if !defined(LUA_USE_C89)
if (base == 2.0) res = l_mathop(log2)(x); else
if (base == l_mathop(2.0))
res = l_mathop(log2)(x); else
#endif
if (base == 10.0) res = l_mathop(log10)(x);
else res = l_mathop(log)(x)/l_mathop(log)(base);
if (base == l_mathop(10.0))
res = l_mathop(log10)(x);
else
res = l_mathop(log)(x)/l_mathop(log)(base);
}
lua_pushnumber(L, res);
return 1;
@ -262,7 +265,7 @@ static int math_random (lua_State *L) {
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,
"interval too large");
r *= (double)(up - low) + 1.0;
@ -281,9 +284,9 @@ static int math_randomseed (lua_State *L) {
static int math_type (lua_State *L) {
if (lua_type(L, 1) == LUA_TNUMBER) {
if (lua_isinteger(L, 1))
lua_pushliteral(L, "integer");
lua_pushliteral(L, "integer");
else
lua_pushliteral(L, "float");
lua_pushliteral(L, "float");
}
else {
luaL_checkany(L, 1);

@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $
** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@ -25,40 +25,9 @@
/*
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH_VAR)
#define LUA_PATH_VAR "LUA_PATH"
#endif
#if !defined(LUA_CPATH_VAR)
#define LUA_CPATH_VAR "LUA_CPATH"
#endif
#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
/*
** LUA_PATH_SEP is the character that separates templates in a path.
** LUA_PATH_MARK is the string that marks the substitution points in a
** template.
** LUA_EXEC_DIR in a Windows path is replaced by the executable's
** directory.
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
#if !defined (LUA_PATH_SEP)
#define LUA_PATH_SEP ";"
#endif
#if !defined (LUA_PATH_MARK)
#define LUA_PATH_MARK "?"
#endif
#if !defined (LUA_EXEC_DIR)
#define LUA_EXEC_DIR "!"
#endif
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
@ -94,7 +63,8 @@ static const int CLIBS = 0;
#define LIB_FAIL "open"
#define setprogdir(L) ((void)0)
#define setprogdir(L) ((void)0)
/*
@ -179,7 +149,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#include <windows.h>
#undef setprogdir
/*
** optional flags for LoadLibraryEx
@ -189,21 +158,30 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif
#undef setprogdir
/*
** Replace in the path (on the top of the stack) any occurrence
** of LUA_EXEC_DIR with the executable's path.
*/
static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff)/sizeof(char);
DWORD n = GetModuleFileNameA(NULL, buff, nsize);
DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName");
else {
*lb = '\0';
*lb = '\0'; /* cut name on the last '\\' to get the path */
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
static void pusherror (lua_State *L) {
int error = GetLastError();
char buffer[128];
@ -272,6 +250,67 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif /* } */
/*
** {==================================================================
** Set Paths
** ===================================================================
*/
/*
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
** variables that Lua check to set its paths.
*/
#if !defined(LUA_PATH_VAR)
#define LUA_PATH_VAR "LUA_PATH"
#endif
#if !defined(LUA_CPATH_VAR)
#define LUA_CPATH_VAR "LUA_CPATH"
#endif
#define AUXMARK "\1" /* auxiliary mark */
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
/*
** Set a path
*/
static void setpath (lua_State *L, const char *fieldname,
const char *envname,
const char *dft) {
const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
const char *path = getenv(nver); /* use versioned name */
if (path == NULL) /* no environment variable? */
path = getenv(envname); /* try unversioned name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, dft); /* use default */
else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
luaL_gsub(L, path, AUXMARK, dft);
lua_remove(L, -2); /* remove result from 1st 'gsub' */
}
setprogdir(L);
lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
lua_pop(L, 1); /* pop versioned variable name */
}
/* }================================================================== */
/*
** return registry.CLIBS[path]
*/
@ -520,7 +559,7 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
@ -557,9 +596,9 @@ static void findloader (lua_State *L, const char *name) {
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
lua_settop(L, 1); /* _LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
lua_getfield(L, 2, name); /* _LOADED[name] */
lua_settop(L, 1); /* LOADED table will be at index 2 */
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_getfield(L, 2, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */
/* else must load package */
@ -569,11 +608,11 @@ static int ll_require (lua_State *L) {
lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */
lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
lua_setfield(L, 2, name); /* _LOADED[name] = true */
lua_setfield(L, 2, name); /* LOADED[name] = true */
}
return 1;
}
@ -666,41 +705,6 @@ static int ll_seeall (lua_State *L) {
/* auxiliary mark (for internal use) */
#define AUXMARK "\1"
/*
** return registry.LUA_NOENV as a boolean
*/
static int noenv (lua_State *L) {
int b;
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
b = lua_toboolean(L, -1);
lua_pop(L, 1); /* remove value */
return b;
}
static void setpath (lua_State *L, const char *fieldname, const char *envname1,
const char *envname2, const char *def) {
const char *path = getenv(envname1);
if (path == NULL) /* no environment variable? */
path = getenv(envname2); /* try alternative name */
if (path == NULL || noenv(L)) /* no environment variable? */
lua_pushstring(L, def); /* use default */
else {
/* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
luaL_gsub(L, path, AUXMARK, def);
lua_remove(L, -2);
}
setprogdir(L);
lua_setfield(L, -2, fieldname);
}
static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib},
{"searchpath", ll_searchpath},
@ -764,19 +768,18 @@ LUAMOD_API int luaopen_package (lua_State *L) {
createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L);
/* set field 'path' */
setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
/* set field 'cpath' */
setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* set paths */
setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field 'loaded' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded");
/* set field 'preload' */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */

@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@ -280,7 +280,7 @@ static const char *l_str2d (const char *s, lua_Number *result) {
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
char *pdot = strchr(s, '.');
const char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
@ -394,7 +394,7 @@ static void pushstr (lua_State *L, const char *str, size_t l) {
/*
** this function handles only '%d', '%c', '%f', '%p', and '%s'
** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/

@ -1,5 +1,5 @@
/*
** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@ -30,16 +30,16 @@
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
@ -257,12 +257,13 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
}
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
const char *option;
int oplen = 1;
for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
static const char *checkoption (lua_State *L, const char *conv,
ptrdiff_t convlen, char *buff) {
const char *option = LUA_STRFTIMEOPTIONS;
int oplen = 1; /* length of options being checked */
for (; *option != '\0' && oplen <= convlen; option += oplen) {
if (*option == '|') /* next block? */
oplen++; /* next length */
oplen++; /* will check options with next length (+1) */
else if (memcmp(conv, option, oplen) == 0) { /* match? */
memcpy(buff, conv, oplen); /* copy valid option to buffer */
buff[oplen] = '\0';
@ -280,8 +281,10 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
size_t slen;
const char *s = luaL_optlstring(L, 1, "%c", &slen);
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
const char *se = s + slen; /* 's' end */
struct tm tmr, *stm;
if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr);
@ -300,13 +303,14 @@ static int os_date (lua_State *L) {
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
while (*s) {
while (s < se) {
if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
s++; /* skip '%' */
s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen);
}

@ -1,11 +1,11 @@
/*
** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/
#define lparser_c
@ -92,65 +92,6 @@ const char *raviY_typename(ravitype_t tt) {
}
}
static void PrintString(FILE *fp, const TString* ts)
{
const char* s = getstr(ts);
size_t i, n = tsslen(ts);
fprintf(fp, "%c", '"');
for (i = 0; i<n; i++)
{
int c = (int)(unsigned char)s[i];
switch (c)
{
case '"': fprintf(fp, "\\\""); break;
case '\\': fprintf(fp, "\\\\"); break;
case '\a': fprintf(fp, "\\a"); break;
case '\b': fprintf(fp, "\\b"); break;
case '\f': fprintf(fp, "\\f"); break;
case '\n': fprintf(fp, "\\n"); break;
case '\r': fprintf(fp, "\\r"); break;
case '\t': fprintf(fp, "\\t"); break;
case '\v': fprintf(fp, "\\v"); break;
default: if (isprint(c))
fprintf(fp, "%c", c);
else
fprintf(fp, "\\%03d", c);
}
}
fprintf(fp, "%c", '"');
}
static void PrintConstant(FILE *fp, const Proto* f, int i)
{
const TValue* o = &f->k[i];
switch (ttype(o))
{
case LUA_TNIL:
fprintf(fp, "nil");
break;
case LUA_TBOOLEAN:
fprintf(fp, bvalue(o) ? "true" : "false");
break;
case LUA_TNUMFLT:
{
char buff[100];
sprintf(buff, LUA_NUMBER_FMT, fltvalue(o));
fprintf(fp, "%s", buff);
if (buff[strspn(buff, "-0123456789")] == '\0') fprintf(fp, ".0");
break;
}
case LUA_TNUMINT:
fprintf(fp, LUA_INTEGER_FMT, ivalue(o));
break;
case LUA_TSHRSTR: case LUA_TLNGSTR:
PrintString(fp, tsvalue(o));
break;
default: /* cannot happen */
fprintf(fp, "? type=%d", ttype(o));
break;
}
}
/* RAVI - prints a Lua expression node */
static void print_expdesc(FILE *fp, FuncState *fs, const expdesc *e) {
char buf[80] = {0};
@ -613,8 +554,8 @@ static void singlevar (LexState *ls, expdesc *var) {
singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key = {.ravi_type = RAVI_TANY, .pc = -1};
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID);
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@ -735,6 +676,8 @@ static void localvar_adjust_assign(LexState *ls, int nvars, int nexps, expdesc *
ravi_setzero(fs, reg, extra);
}
}
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
@ -756,6 +699,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
luaK_nil(fs, reg, extra);
}
}
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
@ -1246,7 +1191,7 @@ static void parlist (LexState *ls) {
}
case TK_DOTS: { /* param -> '...' */
luaX_next(ls);
f->is_vararg = 2; /* declared vararg */
f->is_vararg = 1; /* declared vararg */
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@ -1565,7 +1510,6 @@ static void simpleexp (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs;
check_condition(ls, fs->f->is_vararg,
"cannot use '...' outside a vararg function");
fs->f->is_vararg = 1; /* function actually uses vararg */
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0), RAVI_TANY);
break;
}
@ -1796,8 +1740,6 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
DEBUG_EXPR(raviY_printf(ls->fs, "assignment -> = explist %e\n", &e));
if (nexps != nvars) {
adjust_assign(ls, nvars, nexps, &e);
if (nexps > nvars)
ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
else {
luaK_setoneret(ls->fs, &e); /* close last expression */
@ -2343,7 +2285,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v = {.ravi_type = RAVI_TANY, .pc = -1};
open_func(ls, fs, &bl);
fs->f->is_vararg = 2; /* main function is always declared vararg */
fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0, RAVI_TANY); /* create and... - RAVI TODO var arg is unknown type */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */

@ -29,6 +29,7 @@
#include "ltm.h"
#include "ravijit.h"
#include "ravi_profile.h"
#if !defined(LUAI_GCPAUSE)
#define LUAI_GCPAUSE 200 /* 200% */
@ -318,6 +319,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
global_State *g;
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL;
L = &l->l.l;
@ -362,6 +364,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
close_state(L);
L = NULL;
}
#if RAVI_BYTECODE_PROFILING_ENABLED
raviV_init_profiledata(L);
#endif
return L;
}
@ -369,6 +374,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
LUA_API void lua_close (lua_State *L) {
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
#if RAVI_BYTECODE_PROFILING_ENABLED
raviV_destroy_profiledata(L);
#endif
close_state(L);
}

@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@ -839,11 +839,12 @@ static lua_Number adddigit (char *buff, int n, lua_Number x) {
static int num2straux (char *buff, int sz, lua_Number x) {
if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */
return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */
/* if 'inf' or 'NaN', format it like '%g' */
if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
else if (x == 0) { /* can be -0... */
/* create "0" or "-0" followed by exponent */
return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x);
return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
}
else {
int e;
@ -933,7 +934,7 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = memchr(buff, point, nb);
char *ppoint = (char *)memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
@ -960,7 +961,7 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, n);
nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
}
luaL_addsize(b, nb);
break;
@ -1041,7 +1042,7 @@ static int str_format (lua_State *L) {
case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN);
nb = l_sprintf(buff, MAX_ITEM, form, n);
nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
break;
}
case 'a': case 'A':
@ -1051,8 +1052,9 @@ static int str_format (lua_State *L) {
break;
case 'e': case 'E': case 'f':
case 'g': case 'G': {
lua_Number n = luaL_checknumber(L, arg);
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg));
nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
break;
}
case 'q': {
@ -1259,7 +1261,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
** 'psize' is filled with option's size, 'notoalign' with its
** alignment requirements.
** Local variable 'size' gets the size to be aligned. (Kpadal option
** always gets its full alignment, other options are limited by
** always gets its full alignment, other options are limited by
** the maximum alignment ('maxalign'). Kchar option needs no alignment
** despite its size.
*/

@ -1,5 +1,5 @@
/*
** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $
** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@ -56,28 +56,8 @@
*/
#define MAXHBITS (MAXABITS - 1)
#if !defined(RAVI_ENABLED)
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
#define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p))
#endif
#define dummynode (&dummynode_)
#define isdummy(n) ((n) == dummynode)
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
{{NILCONSTANT, 0}} /* key */
@ -344,14 +324,15 @@ static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
int lsize;
if (size == 0) { /* no elements to hash part? */
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
lsize = 0;
t->lsizenode = 0;
t->hmask = 0;
t->lastfree = NULL; /* signal that it is using dummy node */
}
else {
int i;
lsize = luaO_ceillog2(size);
int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
@ -362,9 +343,10 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
setnilvalue(wgkey(n));
setnilvalue(gval(n));
}
t->lsizenode = cast_byte(lsize);
t->hmask = size - 1;
t->lastfree = gnode(t, size); /* all positions are free */
}
t->lsizenode = cast_byte(lsize);
t->lastfree = gnode(t, size); /* all positions are free */
}
@ -373,7 +355,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int i;
int j;
unsigned int oldasize = t->sizearray;
int oldhsize = t->lsizenode;
int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
@ -390,7 +372,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
}
/* re-insert elements from hash part */
for (j = twoto(oldhsize) - 1; j >= 0; j--) {
for (j = oldhsize - 1; j >= 0; j--) {
Node *old = nold + j;
if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was
@ -398,13 +380,13 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
}
}
if (!isdummy(nold))
luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */
if (oldhsize > 0) /* not the dummy node? */
luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
}
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
int nsize = isdummy(t->node) ? 0 : sizenode(t);
int nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize);
}
@ -490,7 +472,7 @@ void luaH_free (lua_State *L, Table *t) {
luaM_freemem(L, t->ravi_array.data, (t->ravi_array.size*sizeof(lua_Integer)));
}
}
if (!isdummy(t->node))
if (!isdummy(t))
luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
luaM_freearray(L, t->array, t->sizearray);
luaM_free(L, t);
@ -498,10 +480,12 @@ void luaH_free (lua_State *L, Table *t) {
static Node *getfreepos (Table *t) {
while (t->lastfree > t->node) {
t->lastfree--;
if (ttisnil(gkey(t->lastfree)))
return t->lastfree;
if (!isdummy(t)) {
while (t->lastfree > t->node) {
t->lastfree--;
if (ttisnil(gkey(t->lastfree)))
return t->lastfree;
}
}
return NULL; /* could not find a free place */
}
@ -521,7 +505,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
lua_Integer k;
if (luaV_tointeger(key, &k, 0)) { /* index is int? */
if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
setivalue(&aux, k);
key = &aux; /* insert it as an integer */
}
@ -529,7 +513,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
luaG_runerror(L, "table index is NaN");
}
mp = mainposition(t, key);
if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern;
Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */
@ -537,7 +521,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
/* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */
}
lua_assert(!isdummy(f));
lua_assert(!isdummy(t));
othern = mainposition(t, gkey(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
@ -644,8 +628,23 @@ const TValue *luaH_getstr (Table *t, TString *key) {
** main search function
*/
const TValue *luaH_get(Table *t, const TValue *key) {
#if 1
switch (ttype(key)) {
case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
lua_Integer k;
if (luaV_tointeger(key, &k, 0)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */
/* else... */
} /* FALLTHROUGH */
default:
return getgeneric(t, key);
}
#else
int tt = ttype(key);
if (tt == LUA_TNUMINT)
if (RAVI_LIKELY(tt == LUA_TNUMINT))
return luaH_getint(t, ivalue(key));
else if (tt == LUA_TSHRSTR)
return luaH_getshortstr(t, tsvalue(key));
@ -661,6 +660,7 @@ const TValue *luaH_get(Table *t, const TValue *key) {
else {
return getgeneric(t, key);
}
#endif
}
/*
@ -737,7 +737,7 @@ int luaH_getn (Table *t) {
return i;
}
/* else must find a boundary in hash part */
else if (isdummy(t->node)) /* hash part is empty? */
else if (isdummy(t)) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
}
@ -857,7 +857,7 @@ void raviH_get_number_array_rawdata(lua_State *L, Table *t, lua_Number **startp,
lua_assert(t->ravi_array.array_type == RAVI_TARRAYFLT);
lua_Number *data = (lua_Number *)t->ravi_array.data;
*startp = data;
*endp = data + t->ravi_array.len + 1;
*endp = data + t->ravi_array.len;
}
void raviH_get_integer_array_rawdata(lua_State *L, Table *t, lua_Integer **startp, lua_Integer **endp) {
@ -865,7 +865,7 @@ void raviH_get_integer_array_rawdata(lua_State *L, Table *t, lua_Integer **start
lua_assert(t->ravi_array.array_type == RAVI_TARRAYINT);
lua_Integer *data = (lua_Integer *)t->ravi_array.data;
*startp = data;
*endp = data + t->ravi_array.len + 1;
*endp = data + t->ravi_array.len;
}
static const char *key_orig_table = "Originaltable";
@ -934,6 +934,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainposition(t, key);
}
int luaH_isdummy (Node *n) { return isdummy(n); }
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif

@ -1,5 +1,5 @@
/*
** $Id: ltests.c,v 2.209 2015/10/12 16:38:19 roberto Exp $
** $Id: ltests.c,v 2.211 2016/12/04 20:17:24 roberto Exp $
** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h
*/
@ -697,8 +697,8 @@ static int table_query (lua_State *L) {
t = hvalue(obj_at(L, 1));
if (i == -1) {
lua_pushinteger(L, t->sizearray);
lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t));
lua_pushinteger(L, t->lastfree - t->node);
lua_pushinteger(L, allocsizenode(t));
lua_pushinteger(L, isdummy(t) ? 0 : t->lastfree - t->node);
}
else if ((unsigned int)i < t->sizearray) {
lua_pushinteger(L, i);
@ -879,7 +879,7 @@ static int loadlib (lua_State *L) {
luaL_requiref(L1, "package", NULL, 1); /* seg. fault if it reloads */
/* ...but should return the same module */
lua_assert(lua_compare(L1, -1, -2, LUA_OPEQ));
luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD");
luaL_getsubtable(L1, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
for (i = 0; libs[i].name; i++) {
lua_pushcfunction(L1, libs[i].func);
lua_setfield(L1, -2, libs[i].name);

@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@ -15,7 +15,7 @@
#include "lua.h"
#include "ldebug.h"
#include "ldo.h"
#include "ldo.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"

@ -1,5 +1,5 @@
/*
** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $
** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@ -20,6 +20,7 @@
#include "lualib.h"
#if !defined(LUA_PROMPT)
#define LUA_PROMPT "> "
#define LUA_PROMPT2 ">> "
@ -37,8 +38,7 @@
#define LUA_INIT_VAR "LUA_INIT"
#endif
#define LUA_INITVARVERSION \
LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
#ifdef USE_LLVM
#define RAVI_OPTION_STRING3 " LLVM"
@ -64,6 +64,8 @@
#elif defined(LUA_USE_WINDOWS) /* }{ */
#include <io.h>
#include <windows.h>
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else /* }{ */
@ -467,7 +469,7 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
** any invalid argument). 'first' returns the first not-handled argument
** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
*/
static int collectargs (char **argv, int *first) {
@ -491,7 +493,7 @@ static int collectargs (char **argv, int *first) {
args |= has_E;
break;
case 'i':
args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
case 'v':
if (argv[i][2] != '\0') /* extra characters after 1st? */
return has_error; /* invalid option */
@ -539,6 +541,7 @@ static int runargs (lua_State *L, char **argv, int n) {
}
static int handle_luainit (lua_State *L) {
const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1);
@ -599,11 +602,6 @@ static int pmain (lua_State *L) {
return 1;
}
#if 0
// For debugging
LUA_API int ravi_get_modulecount();
#endif
int main (int argc, char **argv) {
int status, result;
lua_State *L = luaL_newstate(); /* create state */
@ -629,10 +627,6 @@ int main (int argc, char **argv) {
result = lua_toboolean(L, -1); /* get result */
report(L, status);
lua_close(L);
#if 0
// For debugging - should be 0
fprintf(stderr, "Modules at exit %d\n", ravi_get_modulecount());
#endif
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

@ -5,7 +5,7 @@
*/
/*
** Portions Copyright (C) 2015-2016 Dibyendu Majumdar
** Portions Copyright (C) 2015-2017 Dibyendu Majumdar
*/
#define lundump_c

@ -1,5 +1,5 @@
/*
** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $
** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
@ -194,7 +194,7 @@ static int byteoffset (lua_State *L) {
lua_pushinteger(L, posi + 1);
else /* no such character */
lua_pushnil(L);
return 1;
return 1;
}

File diff suppressed because it is too large Load Diff

@ -624,7 +624,9 @@ bool ravi_setup_lua_types(ravi_gcc_context_t *ravi) {
// } u;
// ptrdiff_t extra;
// short nresults; /* expected number of results from this function */
// lu_byte callstatus;
// unsigned short callstatus;
// unsigned short stacklevel; /* Ravi extension - stack level, bottom level is 0 */
// lu_byte jitstatus; /* Only valid if Lua function - if 1 means JITed - RAVI extension */
//} CallInfo;
t->CallInfoT =
@ -670,8 +672,13 @@ bool ravi_setup_lua_types(ravi_gcc_context_t *ravi) {
fields[6] =
gcc_jit_context_new_field(ravi->context, NULL, t->C_shortT, "nresults");
fields[7] =
gcc_jit_context_new_field(ravi->context, NULL, t->lu_byteT, "callstatus");
gcc_jit_struct_set_fields(t->CallInfoT, NULL, 8, fields);
gcc_jit_context_new_field(ravi->context, NULL, t->C_shortT, "callstatus");
fields[8] =
gcc_jit_context_new_field(ravi->context, NULL, t->C_shortT, "stacklevel");
fields[9] =
gcc_jit_context_new_field(ravi->context, NULL, t->lu_byteT, "jitstatus");
gcc_jit_struct_set_fields(t->CallInfoT, NULL, 10, fields);
// typedef struct ravi_State ravi_State;
t->ravi_StateT =

@ -29,7 +29,6 @@ namespace ravi {
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
OpCode op, TMS tms, int pc) {
#if 0
bool traced = emit_debug_trace(def, op, pc);
emit_load_base(def);
@ -112,17 +111,16 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
llvm::Value *result = nullptr;
switch (op) {
case OP_ADD:
result = def->builder->CreateAdd(lhs, rhs, "", false, true);
break;
case OP_SUB:
result = def->builder->CreateSub(lhs, rhs, "", false, true);
break;
case OP_MUL:
result = def->builder->CreateMul(lhs, rhs, "", false, true);
break;
default:
lua_assert(0);
case OP_ADD:
result = def->builder->CreateAdd(lhs, rhs, "", false, true);
break;
case OP_SUB:
result = def->builder->CreateSub(lhs, rhs, "", false, true);
break;
case OP_MUL:
result = def->builder->CreateMul(lhs, rhs, "", false, true);
break;
default: lua_assert(0);
}
emit_store_reg_i_withtype(def, result, ra);
@ -146,7 +144,8 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
llvm::BasicBlock::Create(def->jitState->context(), "load.rb");
// If RB is floating then load RB, else convert RB
def->builder->CreateCondBr(cmp1, load_rb, convert_rb);
auto brinst1 = def->builder->CreateCondBr(cmp1, load_rb, convert_rb);
attach_branch_weights(def, brinst1, 100, 0);
// Convert RB
def->f->getBasicBlockList().push_back(convert_rb);
@ -184,7 +183,8 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
// If RC is float load RC
// else try to convert RC
def->builder->CreateCondBr(cmp1, load_rc, convert_rc);
auto brinst2 = def->builder->CreateCondBr(cmp1, load_rc, convert_rc);
attach_branch_weights(def, brinst2, 100, 0);
def->f->getBasicBlockList().push_back(convert_rc);
def->builder->SetInsertPoint(convert_rc);
@ -217,20 +217,11 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
llvm::Value *result = nullptr;
// Add and set RA
switch (op) {
case OP_ADD:
result = def->builder->CreateFAdd(lhs, rhs);
break;
case OP_SUB:
result = def->builder->CreateFSub(lhs, rhs);
break;
case OP_MUL:
result = def->builder->CreateFMul(lhs, rhs);
break;
case OP_DIV:
result = def->builder->CreateFDiv(lhs, rhs);
break;
default:
lua_assert(0);
case OP_ADD: result = def->builder->CreateFAdd(lhs, rhs); break;
case OP_SUB: result = def->builder->CreateFSub(lhs, rhs); break;
case OP_MUL: result = def->builder->CreateFMul(lhs, rhs); break;
case OP_DIV: result = def->builder->CreateFDiv(lhs, rhs); break;
default: lua_assert(0);
}
emit_store_reg_n_withtype(def, result, ra);
@ -252,10 +243,296 @@ void RaviCodeGenerator::emit_ARITH(RaviFunctionDef *def, int A, int B, int C,
#endif
}
// OP_ADD, OP_SUB, OP_MUL and OP_DIV
void RaviCodeGenerator::emit_ARITH_new(RaviFunctionDef *def, int A, int B,
int C, OpCode op, TMS tms, int pc) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
// if (ttisfloat(rb)) {
// if (ttisfloat(rc)) {
// nb = fltvalue(rb); nc = fltvalue(rc);
// setfltvalue(ra, luai_numadd(L, nb, nc));
// }
// else if (ttisinteger(rc)) {
// nb = fltvalue(rb); nc = cast_num(ivalue(rc));
// setfltvalue(ra, luai_numadd(L, nb, nc));
// }
// else slowpath
//}
// else if (ttisinteger(rb)) {
// if (ttisfloat(rc)) {
// nb = cast_num(ivalue(rb)); nc = fltvalue(rc);
// setfltvalue(ra, luai_numadd(L, nb, nc));
// }
// else if (ttisinteger(rc)) {
// lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
// setivalue(ra, intop(+, ib, ic));
// }
// else slowpath
// else slowpath
bool traced = emit_debug_trace(def, op, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
llvm::Value *rb = emit_gep_register_or_constant(def, B);
llvm::Value *rc = emit_gep_register_or_constant(def, C);
llvm::Value *rb_type = emit_load_type(def, rb);
llvm::Value *rc_type = emit_load_type(def, rc);
// PART A - Is RB floating?
llvm::Value *rb_is_float =
emit_is_value_of_type(def, rb_type, LUA__TNUMFLT, "rb.is.float");
llvm::BasicBlock *done =
llvm::BasicBlock::Create(def->jitState->context(), "done");
llvm::BasicBlock *slowpath =
llvm::BasicBlock::Create(def->jitState->context(), "slowpath");
llvm::BasicBlock *check_rc_is_float =
llvm::BasicBlock::Create(def->jitState->context(), "check.rc.is.float");
llvm::BasicBlock *check_rb_is_int =
llvm::BasicBlock::Create(def->jitState->context(), "check.rb.is.int");
// If RB is floating, check RC else check RB is int
auto brinst1 = def->builder->CreateCondBr(rb_is_float, check_rc_is_float,
check_rb_is_int);
attach_branch_weights(def, brinst1, 5, 2);
// Check if rc is float
def->f->getBasicBlockList().push_back(check_rc_is_float);
def->builder->SetInsertPoint(check_rc_is_float);
llvm::Value *rc_is_float =
emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rb.float.is.rc.float");
llvm::BasicBlock *float_op =
llvm::BasicBlock::Create(def->jitState->context(), "float.op");
llvm::BasicBlock *rb_float_check_rc_is_int = llvm::BasicBlock::Create(
def->jitState->context(), "rb.float.check.rc.int");
// RB is floating - so check if RC is floating
auto brinst2 = def->builder->CreateCondBr(rc_is_float, float_op,
rb_float_check_rc_is_int);
attach_branch_weights(def, brinst2, 10, 3);
// Both rb and rc are floats
def->f->getBasicBlockList().push_back(float_op);
def->builder->SetInsertPoint(float_op);
llvm::Instruction *lhs = emit_load_reg_n(def, rb);
llvm::Instruction *rhs = emit_load_reg_n(def, rc);
llvm::Value *result = nullptr;
// Add and set RA
switch (op) {
case OP_ADD: result = def->builder->CreateFAdd(lhs, rhs); break;
case OP_SUB: result = def->builder->CreateFSub(lhs, rhs); break;
case OP_MUL: result = def->builder->CreateFMul(lhs, rhs); break;
case OP_DIV: result = def->builder->CreateFDiv(lhs, rhs); break;
default: lua_assert(0);
}
emit_store_reg_n_withtype(def, result, ra);
// We are done
def->builder->CreateBr(done);
// RB is float - but RC is not, so check if RC is int
def->f->getBasicBlockList().push_back(rb_float_check_rc_is_int);
def->builder->SetInsertPoint(rb_float_check_rc_is_int);
llvm::Value *rb_float_is_rc_int =
emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rb.float.is.rc.int");
llvm::BasicBlock *float_int_op =
llvm::BasicBlock::Create(def->jitState->context(), "float.int.op");
// RB is floating, check if RC in int
auto brinst3 =
def->builder->CreateCondBr(rb_float_is_rc_int, float_int_op, slowpath);
attach_branch_weights(def, brinst3, 100, 0);
// RB is float - but RC is int
def->f->getBasicBlockList().push_back(float_int_op);
def->builder->SetInsertPoint(float_int_op);
lhs = emit_load_reg_n(def, rb);
rhs = emit_load_reg_i(def, rc);
result = nullptr;
// Add and set RA
switch (op) {
case OP_ADD:
result = def->builder->CreateFAdd(
lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
case OP_SUB:
result = def->builder->CreateFSub(
lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
case OP_MUL:
result = def->builder->CreateFMul(
lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
case OP_DIV:
result = def->builder->CreateFDiv(
lhs, def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
default: lua_assert(0);
}
emit_store_reg_n_withtype(def, result, ra);
// We are done
def->builder->CreateBr(done);
// PART B - This section starts by checking whether RB is integer
def->f->getBasicBlockList().push_back(check_rb_is_int);
def->builder->SetInsertPoint(check_rb_is_int);
llvm::Value *rb_is_int =
emit_is_value_of_type(def, rb_type, LUA__TNUMINT, "rb.is.integer");
llvm::BasicBlock *rb_int_check_rc_int =
llvm::BasicBlock::Create(def->jitState->context(), "rb.int.check.rc.int");
llvm::BasicBlock *rb_int_check_rc_float = llvm::BasicBlock::Create(
def->jitState->context(), "rb.int.check.rc.float");
// Check if RB is INT
auto brinst4 =
def->builder->CreateCondBr(rb_is_int, rb_int_check_rc_int, slowpath);
attach_branch_weights(def, brinst4, 100, 0);
// RB is int, check if RC is also int
def->f->getBasicBlockList().push_back(rb_int_check_rc_int);
def->builder->SetInsertPoint(rb_int_check_rc_int);
llvm::Value *rb_int_is_rc_int =
emit_is_value_of_type(def, rc_type, LUA__TNUMINT, "rb.int.is.rc.int");
llvm::BasicBlock *int_int_op =
llvm::BasicBlock::Create(def->jitState->context(), "int.int.op");
// Check if RC is INT
auto brinst5 = def->builder->CreateCondBr(rb_int_is_rc_int, int_int_op,
rb_int_check_rc_float);
attach_branch_weights(def, brinst5, 10, 3);
// RB is int, RC int
def->f->getBasicBlockList().push_back(int_int_op);
def->builder->SetInsertPoint(int_int_op);
// Both are integers
lhs = emit_load_reg_i(def, rb);
rhs = emit_load_reg_i(def, rc);
result = nullptr;
switch (op) {
case OP_ADD:
result = def->builder->CreateAdd(lhs, rhs, "", false, true);
break;
case OP_SUB:
result = def->builder->CreateSub(lhs, rhs, "", false, true);
break;
case OP_MUL:
result = def->builder->CreateMul(lhs, rhs, "", false, true);
break;
case OP_DIV:
result = def->builder->CreateFDiv(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT),
def->builder->CreateSIToFP(rhs, def->types->lua_NumberT));
break;
default: lua_assert(0);
}
if (op != OP_DIV)
emit_store_reg_i_withtype(def, result, ra);
else
emit_store_reg_n_withtype(def, result, ra);
def->builder->CreateBr(done);
// RB is int, check if RC is float
def->f->getBasicBlockList().push_back(rb_int_check_rc_float);
def->builder->SetInsertPoint(rb_int_check_rc_float);
llvm::Value *rb_int_is_rc_float =
emit_is_value_of_type(def, rc_type, LUA__TNUMFLT, "rb.int.is.rc.float");
llvm::BasicBlock *int_float_op =
llvm::BasicBlock::Create(def->jitState->context(), "int.float.op");
// RB is int, check if RC is float
auto brinst6 =
def->builder->CreateCondBr(rb_int_is_rc_float, int_float_op, slowpath);
attach_branch_weights(def, brinst6, 100, 0);
// RB is int, RC is float
def->f->getBasicBlockList().push_back(int_float_op);
def->builder->SetInsertPoint(int_float_op);
lhs = emit_load_reg_i(def, rb);
rhs = emit_load_reg_n(def, rc);
result = nullptr;
// Add and set RA
switch (op) {
case OP_ADD:
result = def->builder->CreateFAdd(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs);
break;
case OP_SUB:
result = def->builder->CreateFSub(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs);
break;
case OP_MUL:
result = def->builder->CreateFMul(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs);
break;
case OP_DIV:
result = def->builder->CreateFDiv(
def->builder->CreateSIToFP(lhs, def->types->lua_NumberT), rhs);
break;
default: lua_assert(0);
}
emit_store_reg_n_withtype(def, result, ra);
// We are done
def->builder->CreateBr(done);
def->f->getBasicBlockList().push_back(slowpath);
def->builder->SetInsertPoint(slowpath);
// Set savedpc as following may invoke metamethod
if (!traced) emit_update_savedpc(def, pc);
switch (op) {
case OP_ADD:
CreateCall4(def->builder, def->raviV_op_addF, def->L, ra, rb, rc);
break;
case OP_SUB:
CreateCall4(def->builder, def->raviV_op_subF, def->L, ra, rb, rc);
break;
case OP_MUL:
CreateCall4(def->builder, def->raviV_op_mulF, def->L, ra, rb, rc);
break;
case OP_DIV:
CreateCall4(def->builder, def->raviV_op_divF, def->L, ra, rb, rc);
break;
default: lua_assert(0);
}
def->builder->CreateBr(done);
def->f->getBasicBlockList().push_back(done);
def->builder->SetInsertPoint(done);
}
// OP_MOD
void RaviCodeGenerator::emit_MOD(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
@ -452,7 +729,6 @@ void RaviCodeGenerator::emit_MOD(RaviFunctionDef *def, int A, int B, int C,
// OP_IDIV
void RaviCodeGenerator::emit_IDIV(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
@ -617,7 +893,6 @@ void RaviCodeGenerator::emit_IDIV(RaviFunctionDef *def, int A, int B, int C,
// OP_POW
void RaviCodeGenerator::emit_POW(RaviFunctionDef *def, int A, int B, int C,
int pc) {
// TValue *rb = RKB(i);
// TValue *rc = RKC(i);
// lua_Number nb; lua_Number nc;
@ -747,7 +1022,6 @@ void RaviCodeGenerator::emit_POW(RaviFunctionDef *def, int A, int B, int C,
}
void RaviCodeGenerator::emit_UNM(RaviFunctionDef *def, int A, int B, int pc) {
// TValue *rb = RB(i);
// lua_Number nb;
// if (ttisinteger(rb)) {

@ -20,8 +20,8 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
#include "ravi_llvmcodegen.h"
#include <ravijit.h>
#include "ravi_llvmcodegen.h"
namespace ravi {
@ -73,7 +73,7 @@ llvm::CallInst *RaviCodeGenerator::CreateCall3(llvm::IRBuilder<> *builder,
llvm::Value *arg1,
llvm::Value *arg2,
llvm::Value *arg3) {
llvm::SmallVector<llvm::Value *, 2> values;
llvm::SmallVector<llvm::Value *, 3> values;
values.push_back(arg1);
values.push_back(arg2);
values.push_back(arg3);
@ -83,7 +83,7 @@ llvm::CallInst *RaviCodeGenerator::CreateCall3(llvm::IRBuilder<> *builder,
llvm::CallInst *RaviCodeGenerator::CreateCall4(
llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4) {
llvm::SmallVector<llvm::Value *, 2> values;
llvm::SmallVector<llvm::Value *, 4> values;
values.push_back(arg1);
values.push_back(arg2);
values.push_back(arg3);
@ -95,7 +95,7 @@ llvm::CallInst *RaviCodeGenerator::CreateCall5(
llvm::IRBuilder<> *builder, llvm::Value *func, llvm::Value *arg1,
llvm::Value *arg2, llvm::Value *arg3, llvm::Value *arg4,
llvm::Value *arg5) {
llvm::SmallVector<llvm::Value *, 2> values;
llvm::SmallVector<llvm::Value *, 5> values;
values.push_back(arg1);
values.push_back(arg2);
values.push_back(arg3);
@ -104,6 +104,15 @@ llvm::CallInst *RaviCodeGenerator::CreateCall5(
return builder->CreateCall(func, values);
}
void RaviCodeGenerator::attach_branch_weights(RaviFunctionDef *def,
llvm::Instruction *ins,
uint32_t true_branch,
uint32_t false_branch) {
ins->setMetadata(llvm::LLVMContext::MD_prof,
def->jitState->types()->mdbuilder.createBranchWeights(
true_branch, false_branch));
}
llvm::Value *RaviCodeGenerator::emit_gep(RaviFunctionDef *def, const char *name,
llvm::Value *s, int arg1, int arg2) {
llvm::SmallVector<llvm::Value *, 2> values;
@ -148,10 +157,9 @@ llvm::Value *RaviCodeGenerator::emit_array_get(RaviFunctionDef *def,
ptr, llvm::ConstantInt::get(def->types->C_intT, offset));
}
// emit code for LClosure *cl = clLvalue(ci->func);
llvm::Instruction *RaviCodeGenerator::emit_gep_ci_func_value_gc_asLClosure(
RaviFunctionDef *def) {
// emit code for
// LClosure *cl = clLvalue(ci->func);
// clLvalue() is a macros that expands to (LClosure *)ci->func->value_.gc
// via a complex series of macros and unions
// fortunately as func is at the beginning of the CallInfo
@ -284,6 +292,7 @@ llvm::Value *RaviCodeGenerator::emit_load_register_or_constant_n(
}
}
// emit code to load the lua_Number value from register (TValue)
llvm::Instruction *RaviCodeGenerator::emit_load_reg_n(RaviFunctionDef *def,
llvm::Value *rb) {
llvm::Value *rb_n = def->builder->CreateBitCast(rb, def->types->plua_NumberT);
@ -293,6 +302,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_reg_n(RaviFunctionDef *def,
return lhs;
}
// emit code to load the lua_Integer value from register (TValue)
llvm::Instruction *RaviCodeGenerator::emit_load_reg_i(RaviFunctionDef *def,
llvm::Value *rb) {
llvm::Value *rb_n =
@ -302,6 +312,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_reg_i(RaviFunctionDef *def,
return lhs;
}
// emit code to load the boolean value from register (TValue)
llvm::Instruction *RaviCodeGenerator::emit_load_reg_b(RaviFunctionDef *def,
llvm::Value *rb) {
llvm::Value *rb_n = def->builder->CreateBitCast(rb, def->types->C_pintT);
@ -310,6 +321,7 @@ llvm::Instruction *RaviCodeGenerator::emit_load_reg_b(RaviFunctionDef *def,
return lhs;
}
// emit code to load the table value from register (TValue)
llvm::Instruction *RaviCodeGenerator::emit_load_reg_h(RaviFunctionDef *def,
llvm::Value *rb) {
llvm::Value *rb_h = def->builder->CreateBitCast(rb, def->types->ppTableT);
@ -318,6 +330,8 @@ llvm::Instruction *RaviCodeGenerator::emit_load_reg_h(RaviFunctionDef *def,
return h;
}
// Gets the size of the hash table
// This is the sizenode() macro in lobject.h
llvm::Value *RaviCodeGenerator::emit_table_get_hashsize(RaviFunctionDef *def,
llvm::Value *t) {
// Obtain the lsizenode of the hash table
@ -334,9 +348,19 @@ llvm::Value *RaviCodeGenerator::emit_table_get_hashsize(RaviFunctionDef *def,
return size;
}
// Gets the location of the hash node for given string key
// return value is the offset into the node array
llvm::Value *RaviCodeGenerator::emit_table_get_hashstr(RaviFunctionDef *def,
llvm::Value *table,
TString *key) {
#if NEW_HASH
unsigned int hash = key->hash;
llvm::Value *hmask_ptr = emit_gep(def, "hmask", table, 0, 12);
llvm::Instruction *hmask = def->builder->CreateLoad(hmask_ptr);
hmask->setMetadata(llvm::LLVMContext::MD_tbaa, def->types->tbaa_Table_hmask);
llvm::Value *offset = def->builder->CreateAnd(
llvm::ConstantInt::get(def->types->C_intT, hash), hmask);
#else
llvm::Value *size = emit_table_get_hashsize(def, table);
unsigned int hash = key->hash;
// #define lmod(s,size) (cast(int, (s) & ((size)-1)))
@ -344,9 +368,11 @@ llvm::Value *RaviCodeGenerator::emit_table_get_hashstr(RaviFunctionDef *def,
def->builder->CreateNSWSub(size, def->types->kInt[1]);
llvm::Value *offset = def->builder->CreateAnd(
llvm::ConstantInt::get(def->types->C_intT, hash), sizeminusone);
#endif
return offset;
}
// Gets access to the Table's node array (t->node)
llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def,
llvm::Value *table) {
// Get access to the node array
@ -356,6 +382,10 @@ llvm::Value *RaviCodeGenerator::emit_table_get_nodearray(RaviFunctionDef *def,
return node;
}
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// type of the value stored at the node - return value is of type int
// and is the type information stored in TValue->tt field.
llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
@ -365,6 +395,9 @@ llvm::Value *RaviCodeGenerator::emit_table_get_keytype(RaviFunctionDef *def,
return ktype;
}
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the string value stored at the node - return value is of type TString*
llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
@ -376,12 +409,16 @@ llvm::Value *RaviCodeGenerator::emit_table_get_strkey(RaviFunctionDef *def,
return keyvalue;
}
// Given a pointer to table's node array (node = t->node) and
// the location of the hashed key (index), this method retrieves the
// the pointer to value stored at the node - return value is of type TValue*
llvm::Value *RaviCodeGenerator::emit_table_get_value(RaviFunctionDef *def,
llvm::Value *node,
llvm::Value *index) {
return emit_gep(def, "nodeval", node, index, 0);
}
// Gets the size of the table's array part
llvm::Value *RaviCodeGenerator::emit_table_get_arraysize(RaviFunctionDef *def,
llvm::Value *table) {
// Obtain the lsizenode of the hash table
@ -484,7 +521,7 @@ void RaviCodeGenerator::emit_store_reg_b_withtype(RaviFunctionDef *def,
void RaviCodeGenerator::emit_store_type_(RaviFunctionDef *def,
llvm::Value *value, int type) {
lua_assert(type == LUA_TNUMFLT || type == LUA_TNUMINT ||
type == LUA_TBOOLEAN);
type == LUA_TBOOLEAN || type == LUA_TNIL);
llvm::Value *desttype = emit_gep(def, "dest.tt", value, 0, 1);
llvm::Instruction *store =
def->builder->CreateStore(def->types->kInt[type], desttype);
@ -622,11 +659,12 @@ llvm::Value *RaviCodeGenerator::emit_gep_register_or_constant(
return rb;
}
// Test if ci->jistatus is true
#if 0
// Test if ci->jistatus is true, ci is of type CallInfo
llvm::Value *RaviCodeGenerator::emit_is_jit_call(RaviFunctionDef *def,
llvm::Value *ci) {
// Get pointer to ci->jitstatus
llvm::Value *ci_jitstatus_ptr = emit_gep(def, "ci_jit_status_ptr", ci, 0, 8);
llvm::Value *ci_jitstatus_ptr = emit_gep(def, "ci_jit_status_ptr", ci, 0, 9);
// Load ci->jitstatus
llvm::Instruction *ci_jitstatus = def->builder->CreateLoad(ci_jitstatus_ptr);
@ -652,11 +690,12 @@ llvm::Value *RaviCodeGenerator::emit_ci_is_Lua(RaviFunctionDef *def,
def->types->tbaa_CallInfo_callstatusT);
llvm::Value *isLua = def->builder->CreateAnd(
ci_callstatus, llvm::ConstantInt::get(def->types->lu_byteT, CIST_LUA),
ci_callstatus, llvm::ConstantInt::get(def->types->C_shortT, CIST_LUA),
"isLua");
return def->builder->CreateICmpNE(
isLua, llvm::ConstantInt::get(def->types->lu_byteT, 0));
isLua, llvm::ConstantInt::get(def->types->C_shortT, 0));
}
#endif
llvm::Value *RaviCodeGenerator::emit_load_ci(RaviFunctionDef *def) {
llvm::Value *L_ci = emit_gep(def, "L_ci", def->L, 0, 6);
@ -723,7 +762,8 @@ llvm::Instruction *RaviCodeGenerator::emit_tointeger(RaviFunctionDef *def,
def->jitState->context(), "if.conversion.failed");
// If reg is integer then copy reg, else convert reg
def->builder->CreateCondBr(cmp1, copy_reg, convert_reg);
auto brinst1 = def->builder->CreateCondBr(cmp1, copy_reg, convert_reg);
attach_branch_weights(def, brinst1, 100, 0);
// Convert RB
def->f->getBasicBlockList().push_back(convert_reg);
@ -778,7 +818,8 @@ llvm::Instruction *RaviCodeGenerator::emit_tofloat(RaviFunctionDef *def,
def->jitState->context(), "if.conversion.failed");
// If reg is integer then copy reg, else convert reg
def->builder->CreateCondBr(cmp1, copy_reg, convert_reg);
auto brinst1 = def->builder->CreateCondBr(cmp1, copy_reg, convert_reg);
attach_branch_weights(def, brinst1, 100, 0);
// Convert RB
def->f->getBasicBlockList().push_back(convert_reg);
@ -1006,6 +1047,11 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->luaH_getstrF = def->raviF->addExternFunction(
def->types->luaH_getstrT, reinterpret_cast<void *>(&luaH_getstr),
"luaH_getstr");
def->luaH_getstrF->addFnAttr(llvm::Attribute::AttrKind::ReadOnly);
def->luaH_getstrF->setDoesNotAlias(1);
def->luaH_getstrF->setDoesNotCapture(1);
def->luaH_getstrF->setDoesNotAlias(2);
def->luaH_getstrF->setDoesNotCapture(2);
def->luaV_finishgetF = def->raviF->addExternFunction(
def->types->luaV_finishgetT, reinterpret_cast<void *>(&luaV_finishget),
"luaV_finishget");
@ -1309,7 +1355,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
// This is the function's activation record / stack frame
def->ci_val = builder.CreateLoad(def->L_ci);
def->ci_val->setMetadata(llvm::LLVMContext::MD_tbaa,
def->types->tbaa_CallInfoT);
def->types->tbaa_luaState_ciT);
// Get pointer to function's 'base' stack location
// 'base' is the address relative to which all the
@ -1622,7 +1668,11 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_RAVI_GETTABLE_SK: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_GETTABLE_SK(def, A, B, C, pc);
lua_assert(ISK(C));
TValue *kv = k + INDEXK(C);
TString *key = tsvalue(kv);
lua_assert(key->tt == LUA_TSHRSTR);
emit_GETTABLE_SK(def, A, B, C, pc, key);
} break;
case OP_GETTABLE: {
int B = GETARG_B(i);
@ -1751,7 +1801,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_ADD: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(def, A, B, C, OP_ADD, TM_ADD, pc);
emit_ARITH_new(def, A, B, C, OP_ADD, TM_ADD, pc);
} break;
case OP_RAVI_ADDFF: {
int B = GETARG_B(i);
@ -1772,7 +1822,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_SUB: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(def, A, B, C, OP_SUB, TM_SUB, pc);
emit_ARITH_new(def, A, B, C, OP_SUB, TM_SUB, pc);
} break;
case OP_RAVI_SUBFF: {
int B = GETARG_B(i);
@ -1798,7 +1848,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_MUL: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(def, A, B, C, OP_MUL, TM_MUL, pc);
emit_ARITH_new(def, A, B, C, OP_MUL, TM_MUL, pc);
} break;
case OP_RAVI_MULFF: {
int B = GETARG_B(i);
@ -1819,7 +1869,7 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
case OP_DIV: {
int B = GETARG_B(i);
int C = GETARG_C(i);
emit_ARITH(def, A, B, C, OP_DIV, TM_DIV, pc);
emit_ARITH_new(def, A, B, C, OP_DIV, TM_DIV, pc);
} break;
case OP_RAVI_DIVFF: {
int B = GETARG_B(i);
@ -1868,10 +1918,10 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
}
}
}
if (doVerify && llvm::verifyFunction(*f->function(), &llvm::errs())) {
f->dump();
fprintf(stderr, "LLVM Code Verification failed\n");
abort();
exit(1);
}
ravi::RaviJITFunction *llvm_func = f.release();
p->ravi_jit.jit_data = reinterpret_cast<void *>(llvm_func);

@ -23,18 +23,6 @@
#include <ravijit.h>
#include "ravi_llvmcodegen.h"
#if 0
// For debugging
static int allocated_modules = 0;
extern "C" {
LUA_API int ravi_get_modulecount() {
return allocated_modules;
}
}
#endif
/*
* Implementation Notes:
* Each Lua function is compiled into an LLVM Module/Function
@ -60,7 +48,8 @@ RaviJITState::RaviJITState()
min_code_size_(150),
min_exec_count_(50),
gc_step_(300),
tracehook_enabled_(false) {
tracehook_enabled_(false),
allocated_modules_(0) {
// LLVM needs to be initialized else
// ExecutionEngine cannot be created
// This needs to be an atomic check although LLVM docs
@ -72,7 +61,7 @@ RaviJITState::RaviJITState()
init++;
}
triple_ = llvm::sys::getProcessTriple();
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MINOR < 7)
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
// On Windows we get compilation error saying incompatible object format
// Reading posts on mailing lists I found that the issue is that COEFF
// format is not supported and therefore we need to set -elf as the object
@ -86,6 +75,7 @@ RaviJITState::RaviJITState()
// Destroy the JIT state freeing up any
// functions that were compiled
RaviJITState::~RaviJITState() {
assert(allocated_modules_ == 0);
delete types_;
delete context_;
}
@ -98,7 +88,6 @@ void RaviJITState::dump() { types_->dump(); }
static std::atomic_int module_id;
RaviJITModule::RaviJITModule(RaviJITState *owner)
: owner_(owner), engine_(nullptr), module_(nullptr) {
int myid = module_id++;
@ -109,27 +98,31 @@ RaviJITModule::RaviJITModule(RaviJITState *owner)
if (myid == 0) {
// Extra validation to check that the LLVM sizes match Lua sizes
llvm::DataLayout *layout = new llvm::DataLayout(module_);
//auto valueSize = layout->getTypeAllocSize(owner->types()->ValueT);
//auto valueSizeOf = sizeof(Value);
//auto TvalueSize = layout->getTypeAllocSize(owner->types()->TValueT);
//auto TvalueSizeOf = sizeof(TValue);
//printf("Value %d %d Tvalue %d %d\n", (int)valueSize, (int)valueSizeOf, (int)TvalueSize, (int)TvalueSizeOf);
// auto valueSize = layout->getTypeAllocSize(owner->types()->ValueT);
// auto valueSizeOf = sizeof(Value);
// auto TvalueSize = layout->getTypeAllocSize(owner->types()->TValueT);
// auto TvalueSizeOf = sizeof(TValue);
// printf("Value %d %d Tvalue %d %d\n", (int)valueSize, (int)valueSizeOf,
// (int)TvalueSize, (int)TvalueSizeOf);
assert(sizeof(Value) == layout->getTypeAllocSize(owner->types()->ValueT));
assert(sizeof(TValue) == layout->getTypeAllocSize(owner->types()->TValueT));
assert(sizeof(UTString) == layout->getTypeAllocSize(owner->types()->TStringT));
assert(sizeof(UTString) ==
layout->getTypeAllocSize(owner->types()->TStringT));
assert(sizeof(Udata) == layout->getTypeAllocSize(owner->types()->UdataT));
assert(sizeof(CallInfo) == layout->getTypeAllocSize(owner->types()->CallInfoT));
assert(sizeof(lua_State) == layout->getTypeAllocSize(owner->types()->lua_StateT));
assert(sizeof(CallInfo) ==
layout->getTypeAllocSize(owner->types()->CallInfoT));
assert(sizeof(lua_State) ==
layout->getTypeAllocSize(owner->types()->lua_StateT));
delete layout;
}
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MINOR < 7)
#if defined(_WIN32) && (!defined(_WIN64) || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7)
// On Windows we get error saying incompatible object format
// Reading posts on mailing lists I found that the issue is that COEFF
// format is not supported and therefore we need to set
// -elf as the object format; LLVM 3.7 onwards COEFF is supported
module_->setTargetTriple(owner->triple());
#endif
#if LLVM_VERSION_MINOR > 5
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 5
// LLVM 3.6.0 change
std::unique_ptr<llvm::Module> module(module_);
llvm::EngineBuilder builder(std::move(module));
@ -141,11 +134,10 @@ RaviJITModule::RaviJITModule(RaviJITState *owner)
std::string errStr;
builder.setErrorStr(&errStr);
engine_ = builder.create();
#if 0
allocated_modules++;
#endif
owner->incr_allocated_modules();
if (!engine_) {
fprintf(stderr, "FATAL ERROR: could not create ExecutionEngine: %s\n", errStr.c_str());
fprintf(stderr, "FATAL ERROR: could not create ExecutionEngine: %s\n",
errStr.c_str());
abort();
return;
}
@ -158,8 +150,8 @@ RaviJITModule::~RaviJITModule() {
// if engine was created then we don't need to delete the
// module as it would have been deleted by the engine
delete module_;
owner_->decr_allocated_modules();
#if 0
allocated_modules--;
//fprintf(stderr, "module destroyed\n");
#endif
}
@ -191,12 +183,12 @@ RaviJITFunction::RaviJITFunction(lua_CFunction *p,
RaviJITFunction::~RaviJITFunction() {
// Remove this function from parent
//fprintf(stderr, "function destroyed\n");
// fprintf(stderr, "function destroyed\n");
module_->removeFunction(this);
}
void RaviJITModule::runpasses(bool dumpAsm) {
#if LLVM_VERSION_MINOR >= 7
#if LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
using llvm::legacy::FunctionPassManager;
using llvm::legacy::PassManager;
#else
@ -220,16 +212,16 @@ void RaviJITModule::runpasses(bool dumpAsm) {
// Set up the optimizer pipeline. Start with registering info about how the
// target lays out data structures.
#if LLVM_VERSION_MINOR == 6
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6
// LLVM 3.6.0 change
module_->setDataLayout(engine_->getDataLayout());
FPM->add(new llvm::DataLayoutPass());
#elif LLVM_VERSION_MINOR == 5
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
// LLVM 3.5.0
auto target_layout = engine_->getTargetMachine()->getDataLayout();
module_->setDataLayout(target_layout);
FPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#elif LLVM_VERSION_MINOR >= 7
#elif LLVM_VERSION_MAJOR > 3 || LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR >= 7
// Apparently no need to set DataLayout
#else
#error Unsupported LLVM version
@ -249,7 +241,7 @@ void RaviJITModule::runpasses(bool dumpAsm) {
// flush; so we introduce a scope here to ensure destruction
// of the stream
llvm::raw_string_ostream ostream(codestr);
#if LLVM_VERSION_MINOR < 7
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 7
llvm::formatted_raw_ostream formatted_stream(ostream);
#else
llvm::buffer_ostream formatted_stream(ostream);
@ -258,9 +250,9 @@ void RaviJITModule::runpasses(bool dumpAsm) {
// Also in 3.7 the pass manager seems to hold on to the stream
// so we need to ensure that the stream outlives the pass manager
std::unique_ptr<PassManager> MPM(new PassManager());
#if LLVM_VERSION_MINOR == 6
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 6
MPM->add(new llvm::DataLayoutPass());
#elif LLVM_VERSION_MINOR == 5
#elif LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR == 5
MPM->add(new llvm::DataLayoutPass(*engine_->getDataLayout()));
#endif
pmb.populateModulePassManager(*MPM);
@ -279,8 +271,8 @@ void RaviJITModule::runpasses(bool dumpAsm) {
}
MPM->run(*module_);
// Note that in 3.7 this flus appears to have no effect
#if LLVM_VERSION_MINOR <= 7
// Note that in 3.7 this flus appears to have no effect
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7
formatted_stream.flush();
#endif
}
@ -321,8 +313,7 @@ llvm::Function *RaviJITModule::addExternFunction(llvm::FunctionType *type,
void *address,
const std::string &name) {
auto fn = external_symbols_.find(name);
if (fn != external_symbols_.end())
return fn->second;
if (fn != external_symbols_.end()) return fn->second;
llvm::Function *f = llvm::Function::Create(
type, llvm::Function::ExternalLinkage, name, module_);
f->setDoesNotThrow();
@ -419,7 +410,7 @@ int raviV_compile(struct lua_State *L, struct Proto *p,
// And put them all in one module
// Returns true if compilation was successful
int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n,
ravi_compile_options_t *options) {
ravi_compile_options_t *options) {
global_State *G = G(L);
int count = 0;
auto module = std::make_shared<ravi::RaviJITModule>(G->ravi_state->jit);

@ -28,9 +28,19 @@ namespace ravi {
void RaviCodeGenerator::emit_LOADNIL(RaviFunctionDef *def, int A, int B,
int pc) {
emit_debug_trace(def, OP_LOADNIL, pc);
#if 1
// Inline version, we unroll the loop
emit_load_base(def);
do {
llvm::Value *dest = emit_gep_register(def, A);
emit_store_type_(def, dest, LUA_TNIL);
A++;
} while (B--);
#else
CreateCall3(def->builder, def->raviV_op_loadnilF, def->ci_val,
llvm::ConstantInt::get(def->types->C_intT, A),
llvm::ConstantInt::get(def->types->C_intT, B));
#endif
}
// R(A) := tonumber(0)
@ -55,7 +65,6 @@ void RaviCodeGenerator::emit_LOADIZ(RaviFunctionDef *def, int A, int pc) {
// R(A) := (Bool)B; if (C) pc++
void RaviCodeGenerator::emit_LOADBOOL(RaviFunctionDef *def, int A, int B, int C,
int j, int pc) {
// setbvalue(ra, GETARG_B(i));
// if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */
@ -91,7 +100,6 @@ void RaviCodeGenerator::emit_MOVE(RaviFunctionDef *def, int A, int B, int pc) {
// R(A) := R(B), check R(B) is int
void RaviCodeGenerator::emit_MOVEI(RaviFunctionDef *def, int A, int B, int pc) {
// TValue *rb = RB(i);
// lua_Integer j;
// if (tointeger(rb, &j)) {
@ -160,7 +168,6 @@ void RaviCodeGenerator::emit_MOVEI(RaviFunctionDef *def, int A, int B, int pc) {
}
void RaviCodeGenerator::emit_MOVEF(RaviFunctionDef *def, int A, int B, int pc) {
// case OP_RAVI_MOVEF: {
// TValue *rb = RB(i);
// lua_Number j;
@ -232,7 +239,6 @@ void RaviCodeGenerator::emit_MOVEF(RaviFunctionDef *def, int A, int B, int pc) {
}
void RaviCodeGenerator::emit_TOINT(RaviFunctionDef *def, int A, int pc) {
// case OP_RAVI_TOINT: {
// lua_Integer j;
// if (tointeger(ra, &j)) {
@ -296,7 +302,6 @@ void RaviCodeGenerator::emit_TOINT(RaviFunctionDef *def, int A, int pc) {
}
void RaviCodeGenerator::emit_TOFLT(RaviFunctionDef *def, int A, int pc) {
// case OP_RAVI_TOFLT: {
// lua_Number j;
// if (tonumber(ra, &j)) {
@ -375,27 +380,29 @@ void RaviCodeGenerator::emit_LOADK(RaviFunctionDef *def, int A, int Bx,
TValue *Konst = &def->p->k[Bx];
switch (Konst->tt_) {
case LUA_TNUMINT:
emit_store_reg_i_withtype(
def, llvm::ConstantInt::get(def->types->lua_IntegerT, Konst->value_.i),
dest);
break;
case LUA_TNUMFLT:
emit_store_reg_n_withtype(
def, llvm::ConstantFP::get(def->types->lua_NumberT, Konst->value_.n),
dest);
break;
case LUA_TBOOLEAN:
emit_store_reg_b_withtype(
def, llvm::ConstantInt::get(def->types->C_intT, Konst->value_.b), dest);
break;
default: {
// rb
llvm::Value *src = emit_gep_constant(def, Bx);
// *ra = *rb
emit_assign(def, dest, src);
}
case LUA_TNUMINT:
emit_store_reg_i_withtype(
def,
llvm::ConstantInt::get(def->types->lua_IntegerT, Konst->value_.i),
dest);
break;
case LUA_TNUMFLT:
emit_store_reg_n_withtype(
def, llvm::ConstantFP::get(def->types->lua_NumberT, Konst->value_.n),
dest);
break;
case LUA_TBOOLEAN:
emit_store_reg_b_withtype(
def, llvm::ConstantInt::get(def->types->C_intT, Konst->value_.b),
dest);
break;
default: {
// rb
llvm::Value *src = emit_gep_constant(def, Bx);
// *ra = *rb
emit_assign(def, dest, src);
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save