From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: nalaginrut Newsgroups: gmane.lisp.guile.devel Subject: New feature proposal: Support C-code inline? Date: Wed, 20 Apr 2011 17:50:13 +0800 Organization: HFG Message-ID: <1303293013.2749.41.camel@Renee-desktop> Reply-To: NalaGinrut@gmail.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-g8/42AUS8rG2OUSsI939" X-Trace: dough.gmane.org 1303293134 29872 80.91.229.12 (20 Apr 2011 09:52:14 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 20 Apr 2011 09:52:14 +0000 (UTC) To: guile-devel Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Wed Apr 20 11:52:10 2011 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QCU4v-0002Pt-Un for guile-devel@m.gmane.org; Wed, 20 Apr 2011 11:52:10 +0200 Original-Received: from localhost ([::1]:47528 helo=lists2.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCU4v-0003pm-H7 for guile-devel@m.gmane.org; Wed, 20 Apr 2011 05:52:09 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:37381) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCU4r-0003pW-Jj for guile-devel@gnu.org; Wed, 20 Apr 2011 05:52:06 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QCU4q-0001DC-4i for guile-devel@gnu.org; Wed, 20 Apr 2011 05:52:05 -0400 Original-Received: from mail-pw0-f41.google.com ([209.85.160.41]:44354) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QCU4p-0001D8-SR for guile-devel@gnu.org; Wed, 20 Apr 2011 05:52:04 -0400 Original-Received: by pwi10 with SMTP id 10so481022pwi.0 for ; Wed, 20 Apr 2011 02:52:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:subject:from:reply-to:to:content-type :organization:date:message-id:mime-version:x-mailer; bh=gB//YHQPqASOKuhYPCv+n7KNwBNvvKE/sBKPR00CURg=; b=Zh74yjR4omCKdBagzO5chkxp2Z8wGnUTPUhXPMIO03QN/v8DHpO/mdaUPrYQ2rIiL2 /1rcjUSKwcgeBTet5Fkg89J7mVeAdlP55zXvuFwRybR54O9gHV+RoklyyBSTlasYrm6h 32N66560EN2dboIQicIlaNaNM/V7VshkhuFY8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=subject:from:reply-to:to:content-type:organization:date:message-id :mime-version:x-mailer; b=wuk/FQZCXUSHDZZlBGQVLcx73bNdCZHhKTpsktTstsTNMHZXpjLY8/IoNDzqLOYrlE 3MEwzJGKFH4IaDutOoAowPRFgrKmw+50/e7ImyM2ckCOlFiHLzHxiornNGELV50oqtW+ XPe+tGTklFdT5FwyXduQOsl3Xf6k5T9YitNd8= Original-Received: by 10.68.9.38 with SMTP id w6mr9548639pba.431.1303293122547; Wed, 20 Apr 2011 02:52:02 -0700 (PDT) Original-Received: from [192.168.100.100] ([183.15.157.253]) by mx.google.com with ESMTPS id p7sm531570pbi.58.2011.04.20.02.51.56 (version=SSLv3 cipher=OTHER); Wed, 20 Apr 2011 02:52:01 -0700 (PDT) X-Mailer: Evolution 2.28.3 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.160.41 X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:12292 Archived-At: --=-g8/42AUS8rG2OUSsI939 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit hi all! I think somebody will need such a C-inline feature when he wants to write a smart C-function to replace the critical function in his algorithm. And I found a similar feature in Ruby. So I wrote a module to provide this. Anyway, I think the best solution is a AOT compiler for guile. But it seems to be dystocia. So this module provides an easy solution. Let me show it's usage: (use-modules (inline inline)) (define in (make #:name "mytest")) ;; this name is arbitrary. But if you made more than one inline instance ;; in your program, each must has an unique name. Or shit happens. (inline:eat-code in "int func(int a ,int b){ return a+b;}") ;; well~this example is too stupid. Try another as you will... (let ((myfunc (inline:get in))) (myfunc 5 6) ) ===> 11 Drawback: 1. Though this module will parse the function type list, it's not perfect. Users can only chose "int/float/double/char/long/void". 2. Can't support "unsigned" in the function declaration. But you can use them in the function body. 3. Can't support "pointers" in the function declaration, it's a big drawback. This inline feature is restricted so much because of this pity. The good news is you can use it in the function body. 4. ...Anyone find more? Future: 1. Fix the known drawbacks. 2. Each inline instance will generate a share lib file. That means each inline function will have one share lib file. Though they won't conflict because the lib file name is bound to the program name which use it, I think it's not proper. Maybe we can add several inline functions to one inline instance, and generate just one share lib for each program. I don't know how much people is interested it. For some low-level programming guys, this module even provides inline assemble. I know this module is too simple for some guys, but it's easy to implement and easy to use. My patch is attached(actually it's not a patch...). Any advices? -- GNU Powered it GPL Protected it GOD Blessed it HFG - NalaGinrut --hacker key-- v4sw7CUSMhw6ln6pr8OSFck4ma9u8MLSOFw3WDXGm7g/l8Li6e7t4TNGSb8AGORTDLMen6g6RASZOGCHPa28s1MIr4p-x hackerkey.com ---end key--- --=-g8/42AUS8rG2OUSsI939 Content-Disposition: attachment; filename="inline.scm" Content-Type: text/x-scheme; name="inline.scm"; charset="UTF-8" Content-Transfer-Encoding: 7bit ;; guile-inline ;; Copyright (C) 2011 ;; NalaGinrut ;; This library is free software; you can redistribute it and/or modify ;; it under the terms of the GNU Lesser General Public License as ;; published by the Free Software Foundation; either version 3 of the ;; License, or (at your option) any later version. ;; ;; This library is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; Lesser General Public License for more details. ;; ;; You should have received a copy of the GNU Lesser General Public ;; License along with this program; if not, contact: ;; ;; Free Software Foundation Voice: +1-617-542-5942 ;; 59 Temple Place - Suite 330 Fax: +1-617-542-2652 ;; Boston, MA 02111-1307, USA gnu@gnu.org (define-module (inline inline) #:use-module (oop goops) #:use-module (ice-9 regex) #:use-module (system foreign) #:export ( inline:eat-code inline:get ) ) (define type-regexp "([A-Za-z0-9_]+) ([A-Za-z0-9_]+)\\(([A-Z0-9a-z_ ,]*)\\)") (define arg-type-regexp "([a-zA-Z0-9_]+) [a-zA-Z0-9_]+") (define func-type 1) (define func-name 2) (define args 3) (define fname 0) (define fargs 1) (define ftype 2) (define fargs-types 3) (define match-decl (lambda (decl) (lambda (which) (match:substring (string-match type-regexp decl) which)))) (define get-args-type-list (lambda (args) (let* ((al (string-split args #\,)) (sl (map (lambda (x) (string->type (match:substring (string-match arg-type-regexp x) 1))) al)) ) sl ))) (define string->type (lambda (str) (eval (string->symbol str) (current-module)))) (define gen-load-path (lambda () (string-append %compile-fallback-path (getcwd) "/"))) (define-class () ;; this name will be the .so file name (name #:init-value "example" #:init-keyword #:name) (so-path #:init-form (gen-load-path) #:init-keyword #:so-path) (tmp-path #:init-value "/tmp/") ;; target name with complete path (target #:init-value #f #:accessor inline:target) ;; func is C-side function info (info #:init-value #f #:accessor inline:info) ;; keep the code string in case we need regenerate .so (code #:init-value #f #:accessor inline:code) ;; this is dynamic FFI (ffi #:init-value #f #:accessor inline:ffi) ) (define-method (inline:gen-so (in )) (let* (;; NOTE: I chose -fpic which implies -msmall-data ;; And I think inline code must be smart.So ;; please take care of this. (name (slot-ref in 'name)) (c-name (string-append (slot-ref in 'tmp-path) name ".c")) (so-name (string-append (slot-ref in 'so-path) (basename (car (command-line))) "." name ".so")) (cc-cmd (string-append "cc -shared -fpic " c-name " -o" so-name)) (code (inline:code in)) (output (open-file c-name "w")) ) ;; write C code to a tmp file (format output "~a~%" code) (close output) (if (eqv? (system cc-cmd) 0) (set! (inline:target in) so-name) (error inline:gen-so "compile inline function error") ))) (define-method (inline:update-code (in ) (code )) (if (not (inline:code in)) (set! (inline:code in) code))) (define-method (inline:update-info (in ) (info )) (if (not (inline:code in)) (set! (inline:info in) info))) (define-method (inline:update-ffi (in )) (let* ((so-file (inline:target in)) (dso (dynamic-link so-file)) (info (inline:info in)) (fn (list-ref info fname)) (args (list-ref info fargs)) (ft (list-ref info ftype)) (at (list-ref info fargs-types)) (ffi (pointer->procedure ft (dynamic-func fn dso) at )) ) (set! (inline:ffi in) ffi) )) (define-method (inline:eat-code (in ) (code )) (let* ((decl (string-copy code 0 (string-index code #\{))) (match-type (match-decl decl)) (ft (string->type (match-type func-type))) (args (match-type args)) (at (get-args-type-list args)) (fn (match-type func-name)) (info (list fn args ft at)) ) (inline:update-info in info) (inline:update-code in code) ;; generate .so file (inline:gen-so in) (inline:update-ffi in) )) (define-method (inline:get (in )) (let* ((target (inline:target in)) (code (inline:code in)) (status #f) ) ;; if target isn't exist, re-generate it. (if (not target) (inline:eat-code in code)) (set! status (stat target)) ;; if target is newer than last accession, ;; update the ffi. (if (> (stat:mtime status) (stat:atime status)) (inline:update-ffi in)) ;; return ffi (inline:ffi in) )) --=-g8/42AUS8rG2OUSsI939--