11

Low-Level Programming

Slogan, by design, is a high-level language, allowing you to build systems without being concerned too much about how the underlying hardware works. For instance, the programmer need not worry about how memory is allocated for objects involved in a computation and how that memory is returned to the system once the computation is over. Memory management is fully automated by the Slogan runtime system. Despite being a high-level, dynamic language, Slogan programs are compiled to efficient machine code that can sometimes rival the performance of statically typed languages.

While it's possible to write high-performance applications entirely in Slogan, situations may arise where a program needs direct access to platform specific libraries. Examples of such libraries include hardware drivers and database clients. Sometimes the programmer may like to have more control on how the application makes use of resources like memory and optimize a critical part of the program for performance. Requirements like this makes it necessary to enable Slogan programs to integrate libraries written in system programming languages like C and C++. The Foreign Function Interface (FFI) is a framework designed for this purpose.

Let us see how to create Slogan bindings to functions and structures defined in a small C library. The C library itself does not do anything fancy. It export two functions – one for creating a structure that represents a Cartesian point and another function for scaling a Cartesian point by a given factor. The code for the library is shown below:


// sample_c_lib.c

// Compile to a shared library (Linux):
// $ gcc -Wall -shared -fPIC -o sample_c_lib.so sample_c_lib.c

// Compile to a shared library (OS X):
// $ gcc -dynamiclib -Wl,-undefined -Wl,dynamic_lookup -o sample_c_lib.so sample_c_lib.c

#include <stdlib.h>

struct point {
   int x;
   int y;
};

struct point make_point(int x, int y)
{
   struct point p = {x, y};
   return p;
}

struct point scale_point(struct point p, int factor)
{
  struct point fp = {p.x * factor, p.y * factor};
  return fp;
}
      

We should introduce the signatures of the definitions in the shared library to the Slogan program that wants to use it:


declare ffi "sample_c_lib.so"
[struct point [int:x, int:y],
 point make_point [int, int],
 point scale_point [point, int]]
      

After these declarations, the Slogan program can call the C functions, just like it would call normal Slogan functions.


let p = make_point(10, 20)
p
// [0, x:10, y:20]
let p2 = scale_point(p, 5)
p2
[0, x:50, y:100]
      

The declare ffi statement has the following syntax:


declare ffi <library_name> <list_of_prototypes>
      

Library_name must be a string or an identifier. If it is a string, it must be the full or relative path of the C library to be loaded. If the path is relative, the library is first looked up in the local folder and then under the paths specified by the LD_LIBRARY_PATH environment variable.

If library_name is an identifier it must point to a library object loaded by the ffi_open function.

List_of_prototypes contain prototype declarations of functions and structures in the C library. The Slogan compiler use these declarations to create functions that act as proxies to access C objects.

The syntax of a function prototype is shown below:


<return_type> <c_function_name> <list_of_argument_types> as <proxy_function_name>
      

Proxy_function_name is optional. If provided, the Slogan function that acts as a proxy will be bound to this name. Otherwise it will be bound to c_function_name.

The following table list type names that can be used in a prototype and their equivalent C-types:

Type Equivalent C-type
uint8 uint8_t
int8 int8_t
uint16 uint16_t
int16 int16_t
uint32 uint32_t
int32 int32_t
uchar unsigned char
char signed char
ushort unsigned short
short signed short
uint unsigned int
int signed int
ulong unsigned long
long signed long
uint64 uint64_t
int64 int64_t
float float
double double
longdouble long double
charstring char *
pointer void *
void void

Note that the void type can only be used as a return type. It cannot be used as the type of a parameter.

The syntax of the specification for a C struct is as follows:


struct <struct_name> <list_of_struct_members>
      

List_of_struct_members is an association list (a list of pairs) that map types and names of a struct member.

Slogan allow even finer grained control over how a shared library is loaded into a program's address space and how C functions are mapped to into the program. It is also possible to call Slogan functions from a C program! Please see the reference documentation on the ffi_open and ___call_fn functions for more details.


Next | Previous | Contents