diff --git a/DEPRECATED.pod b/DEPRECATED.pod index 76a372a..92eedb5 100644 --- a/DEPRECATED.pod +++ b/DEPRECATED.pod @@ -74,6 +74,13 @@ so this usage will not be allowed. L +=item Use of 'v' in NCI parameter lists [eligible in 2.1] + +An empty parameter list suffices to indicate no parameters to an NCI call. +This has been marked as deprecated in PDD16 for 2 years. + +F + =back =head1 Opcodes diff --git a/MANIFEST b/MANIFEST index f13572d..e0d092a 100644 --- a/MANIFEST +++ b/MANIFEST @@ -234,9 +234,6 @@ config/auto/env/test_setenv_c.in [] config/auto/env/test_unsetenv_c.in [] config/auto/format.pm [] config/auto/frames.pm [] -config/auto/frames/test_exec_cygwin_c.in [] -config/auto/frames/test_exec_linux_c.in [] -config/auto/frames/test_exec_openbsd_c.in [] config/auto/gc.pm [] config/auto/gc/test_c.in [] config/auto/gcc.pm [] @@ -258,6 +255,8 @@ config/auto/inline/test2_c.in [] config/auto/isreg.pm [] config/auto/isreg/test_c.in [] config/auto/jit.pm [] +config/auto/libjit.pm [] +config/auto/libjit/libjit_c.in [] config/auto/memalign.pm [] config/auto/memalign/test2_c.in [] config/auto/memalign/test_c.in [] @@ -310,6 +309,9 @@ config/gen/core_pmcs.pm [] config/gen/crypto.pm [] config/gen/crypto/digest_pmc.in [] config/gen/crypto/digest_t.in [] +config/gen/libjit.pm [] +config/gen/libjit/frame_builder_libjit_c.in [] +config/gen/libjit/frame_builder_libjit_h.in [] config/gen/makefiles.pm [] config/gen/makefiles/CFLAGS.in [] config/gen/makefiles/data_json.in [] @@ -1269,7 +1271,6 @@ src/events.c [] src/exceptions.c [] src/exit.c [] src/extend.c [] -src/frame_builder.c [] src/frame_builder.h [] src/gc/alloc_memory.c [] src/gc/alloc_resources.c [] @@ -1940,6 +1941,7 @@ t/steps/auto/icu-01.t [test] t/steps/auto/inline-01.t [test] t/steps/auto/isreg-01.t [test] t/steps/auto/jit-01.t [test] +t/steps/auto/libjit-01.t [test] t/steps/auto/memalign-01.t [test] t/steps/auto/msvc-01.t [test] t/steps/auto/neg_0-01.t [test] @@ -1964,6 +1966,7 @@ t/steps/gen/config_h-01.t [test] t/steps/gen/config_pm-01.t [test] t/steps/gen/core_pmcs-01.t [test] t/steps/gen/crypto-01.t [test] +t/steps/gen/libjit-01.t [test] t/steps/gen/makefiles-01.t [test] t/steps/gen/opengl-01.t [test] t/steps/gen/parrot_include-01.t [test] diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP index 38d117d..772755c 100644 --- a/MANIFEST.SKIP +++ b/MANIFEST.SKIP @@ -1,6 +1,6 @@ # ex: set ro: # $Id$ -# generated by tools/dev/mk_manifest_and_skip.pl Sun Sep 27 09:00:39 2009 UT +# generated by tools/dev/mk_manifest_and_skip.pl Sun Oct 18 15:34:28 2009 UT # # This file should contain a transcript of the svn:ignore properties # of the directories in the Parrot subversion repository. (Needed for @@ -653,6 +653,10 @@ ^src/extend_vtable\.c/ ^src/fingerprint\.c$ ^src/fingerprint\.c/ +^src/frame_builder_libjit\.c$ +^src/frame_builder_libjit\.c/ +^src/frame_builder_libjit\.h$ +^src/frame_builder_libjit\.h/ ^src/glut_callbacks\.c$ ^src/glut_callbacks\.c/ ^src/install_config\.c$ diff --git a/MANIFEST.generated b/MANIFEST.generated index 528843c..8e9aa7c 100644 --- a/MANIFEST.generated +++ b/MANIFEST.generated @@ -1,4 +1,5 @@ # $Id$ +# Please re-sort this file after *EVERY* modification # See tools/dev/install_files.pl for documentation on the # format of this file. # Please re-sort this file after *EVERY* modification @@ -7,6 +8,7 @@ blib/lib/libparrot.a [main]lib blib/lib/libparrot.dylib [main]lib blib/lib/libparrot.so.1.7.0 [main]lib blib/lib/libparrot.so [main]lib +blib/lib/libparrot.so.1.6.0 [main]lib compilers/data_json/data_json.pbc [data_json] compilers/json/JSON.pbc [json] compilers/json/JSON/grammar.pbc [json] @@ -37,9 +39,9 @@ include/parrot/exec_dep.h [main]include include/parrot/extend_vtable.h [main]include include/parrot/feature.h [main]include include/parrot/has_header.h [main]include +include/parrot/oplib/core_ops.h [main]include include/parrot/oplib/core_ops_cg.h [main]include include/parrot/oplib/core_ops_cgp.h [main]include -include/parrot/oplib/core_ops.h [main]include include/parrot/oplib/core_ops_switch.h [main]include include/parrot/oplib/ops.h [main]include include/parrot/pbcversion.h [devel]include @@ -48,30 +50,28 @@ include/parrot/platform_interface.h [main]include include/parrot/platform_limits.h [devel]include include/parrot/vtable.h [main]include install_config.fpmc [main]lib -src/install_config.o [main]lib -src/install_config.obj [main]lib -installable_parrot_config.exe [main]bin +installable_parrot [main]bin +installable_parrot.exe [main]bin installable_parrot_config [main]bin -installable_parrot_debugger.exe [main]bin +installable_parrot_config.exe [main]bin installable_parrot_debugger [main]bin -installable_parrot.exe [main]bin -installable_parrot [main]bin -installable_pbc_disassemble.exe [main]bin +installable_parrot_debugger.exe [main]bin +installable_parrot_nqp [main]bin +installable_parrot_nqp.exe [main]bin installable_pbc_disassemble [main]bin -installable_pbc_dump.exe [main]bin +installable_pbc_disassemble.exe [main]bin installable_pbc_dump [main]bin -installable_pbc_merge.exe [main]bin +installable_pbc_dump.exe [main]bin installable_pbc_merge [main]bin -installable_pbc_to_exe.exe [main]bin +installable_pbc_merge.exe [main]bin installable_pbc_to_exe [main]bin -installable_parrot_nqp.exe [main]bin -installable_parrot_nqp [main]bin +installable_pbc_to_exe.exe [main]bin lib/Parrot/Config/Generated.pm [devel]lib -libparrot.dll [main]bin -libparrot.lib [main]bin lib/Parrot/OpLib/core.pm [devel]lib -lib/Parrot/Pmc2c/PCCMETHOD_BITS.pm [devel]lib lib/Parrot/PMC.pm [devel]lib +lib/Parrot/Pmc2c/PCCMETHOD_BITS.pm [devel]lib +libparrot.dll [main]bin +libparrot.lib [main]bin parrot.pc [main]pkgconfig runtime/parrot/dynext/digest_group.bundle [library] runtime/parrot/dynext/digest_group.dll [library] @@ -97,10 +97,10 @@ runtime/parrot/dynext/match_group.bundle [library] runtime/parrot/dynext/match_group.dll [library] runtime/parrot/dynext/match_group.dylib [library] runtime/parrot/dynext/match_group.so [library] -runtime/parrot/dynext/math_ops.so [library] runtime/parrot/dynext/math_ops.bundle [library] runtime/parrot/dynext/math_ops.dll [library] runtime/parrot/dynext/math_ops.dylib [library] +runtime/parrot/dynext/math_ops.so [library] runtime/parrot/dynext/obscure_ops.bundle [library] runtime/parrot/dynext/obscure_ops.dll [library] runtime/parrot/dynext/obscure_ops.dylib [library] @@ -145,48 +145,45 @@ runtime/parrot/include/vtable_methods.pasm [main] runtime/parrot/include/warnings.pasm [main] runtime/parrot/library/CGI/QueryHash.pbc [main] runtime/parrot/library/Config/JSON.pbc [main] +<<<<<<< HEAD +======= runtime/parrot/library/Configure.pbc [main] runtime/parrot/library/config.pbc [main] runtime/parrot/library/config.pir [main] +>>>>>>> master runtime/parrot/library/Crow.pbc [main] +runtime/parrot/library/Data/Dumper.pbc [main] runtime/parrot/library/Data/Dumper/Base.pbc [main] runtime/parrot/library/Data/Dumper/Default.pbc [main] -runtime/parrot/library/Data/Dumper.pbc [main] runtime/parrot/library/Data/Replace.pbc [main] runtime/parrot/library/Digest/MD5.pbc [main] -runtime/parrot/library/dumper.pbc [main] runtime/parrot/library/Getopt/Obj.pbc [main] runtime/parrot/library/HTTP/Daemon.pbc [main] runtime/parrot/library/Iter.pbc [main] runtime/parrot/library/JSON.pbc [main] -runtime/parrot/library/libpcre.pbc [main] -runtime/parrot/library/Math/Random/mt19937ar.pbc [main] -runtime/parrot/library/Math/Rand.pbc [main] runtime/parrot/library/MIME/Base64.pbc [main] +runtime/parrot/library/Math/Rand.pbc [main] +runtime/parrot/library/Math/Random/mt19937ar.pbc [main] runtime/parrot/library/NCI/call_toolkit_init.pbc [main] -runtime/parrot/library/ncurses.pbc [main] -runtime/parrot/library/OpenGL_funcs.pir [main] -runtime/parrot/library/OpenGL_funcs.pbc [main] runtime/parrot/library/OpenGL.pbc [main] +runtime/parrot/library/OpenGL_funcs.pbc [main] +runtime/parrot/library/OpenGL_funcs.pir [main] runtime/parrot/library/P6object.pbc [main] -runtime/parrot/library/Parrot/Capture_PIR.pbc [main] -runtime/parrot/library/Parrot/Coroutine.pbc [main] -runtime/parrot/library/Parrot/Exception.pbc [main] -runtime/parrot/library/Parrot/HLLCompiler.pbc [main] -runtime/parrot/library/parrotlib.pbc [main] -runtime/parrot/library/pcore.pbc [main] -runtime/parrot/library/pcre.pbc [main] +runtime/parrot/library/PCT.pbc [main] runtime/parrot/library/PCT/Grammar.pbc [main] runtime/parrot/library/PCT/HLLCompiler.pbc [main] runtime/parrot/library/PCT/PAST.pbc [main] -runtime/parrot/library/PCT.pbc [main] +runtime/parrot/library/PGE.pbc [main] runtime/parrot/library/PGE/Dumper.pbc [main] runtime/parrot/library/PGE/Glob.pbc [main] runtime/parrot/library/PGE/Hs.pbc [main] -runtime/parrot/library/PGE.pbc [main] runtime/parrot/library/PGE/Perl6Grammar.pbc [main] runtime/parrot/library/PGE/Text.pbc [main] runtime/parrot/library/PGE/Util.pbc [main] +runtime/parrot/library/Parrot/Capture_PIR.pbc [main] +runtime/parrot/library/Parrot/Coroutine.pbc [main] +runtime/parrot/library/Parrot/Exception.pbc [main] +runtime/parrot/library/Parrot/HLLCompiler.pbc [main] runtime/parrot/library/Protoobject.pbc [main] runtime/parrot/library/Range.pbc [main] runtime/parrot/library/Stream/Base.pbc [main] @@ -198,22 +195,34 @@ runtime/parrot/library/Stream/ParrotIO.pbc [main] runtime/parrot/library/Stream/Replay.pbc [main] runtime/parrot/library/Stream/Sub.pbc [main] runtime/parrot/library/Stream/Writer.pbc [main] +runtime/parrot/library/TGE.pbc [tge] runtime/parrot/library/Tcl/Glob.pbc [main] runtime/parrot/library/TclLibrary.pbc [main] +runtime/parrot/library/Test/Builder.pbc [main] +runtime/parrot/library/Test/Builder/Output.pbc [main] runtime/parrot/library/Test/Builder/Test.pbc [main] -runtime/parrot/library/Test/Builder/Tester.pbc [main] runtime/parrot/library/Test/Builder/TestPlan.pbc [main] -runtime/parrot/library/Test/Builder/Output.pbc [main] -runtime/parrot/library/Test/Builder.pbc [main] +runtime/parrot/library/Test/Builder/Tester.pbc [main] runtime/parrot/library/Test/Class.pbc [main] runtime/parrot/library/Test/More.pbc [main] -runtime/parrot/library/TGE.pbc [tge] -runtime/parrot/library/uuid.pbc [main] +runtime/parrot/library/YAML/Dumper.pbc [main] runtime/parrot/library/YAML/Dumper/Base.pmc [main] runtime/parrot/library/YAML/Dumper/Default.pmc [main] -runtime/parrot/library/YAML/Dumper.pbc [main] +runtime/parrot/library/config.pbc [main] +runtime/parrot/library/config.pir [main] +runtime/parrot/library/dumper.pbc [main] +runtime/parrot/library/libpcre.pbc [main] +runtime/parrot/library/ncurses.pbc [main] +runtime/parrot/library/parrotlib.pbc [main] +runtime/parrot/library/pcore.pbc [main] +runtime/parrot/library/pcre.pbc [main] +runtime/parrot/library/uuid.pbc [main] src/call_list.txt [devel]src +src/frame_builder_libjit.c [devel]src +src/frame_builder_libjit.h [devel]src src/glut_callbacks.c [] +src/install_config.o [main]lib +src/install_config.obj [main]lib src/jit_emit.h [] src/nci.c [] src/null_config.c [] diff --git a/config/auto/frames.pm b/config/auto/frames.pm index f6f7d67..519b44e 100644 --- a/config/auto/frames.pm +++ b/config/auto/frames.pm @@ -40,21 +40,13 @@ sub runstep { sub _call_frames_buildable { my $conf = shift; - - my $osname = $conf->data->get('osname'); - my $cpuarch = $conf->data->get('cpuarch'); - my $nvsize = $conf->data->get('nvsize'); my $can_build_call_frames; if (defined $conf->options->get('buildframes')) { $can_build_call_frames = $conf->options->get('buildframes'); } else { - # TT #1132 - # Temporary disable build frames automatically. - #$can_build_call_frames = ($nvsize == 8 && $cpuarch eq 'i386' - # && $osname ne 'darwin'); - $can_build_call_frames = 0; + $can_build_call_frames = $conf->data->get('HAS_LIBJIT'); } return $can_build_call_frames; } @@ -63,36 +55,13 @@ sub _handle_can_build_call_frames { my ($self, $conf, $can_build_call_frames) = @_; if ( $can_build_call_frames ) { $conf->data->set( - cc_build_call_frames => '-DCAN_BUILD_CALL_FRAMES', + cc_build_call_frames => '-DCAN_BUILD_CALL_FRAMES', + has_exec_protect => 1, ); - # test for executable malloced memory - my $osname = $conf->data->get( 'osname' ); - if ( -e "config/auto/frames/test_exec_${osname}_c.in" ) { - $conf->cc_gen("config/auto/frames/test_exec_${osname}_c.in"); - eval { $conf->cc_build(); }; - if ($@) { - $conf->data->set( has_exec_protect => 0 ); - } - else { - my $exec_protect_test = ( - $conf->cc_run(0) !~ /ok/ && $conf->cc_run(1) =~ /ok/ - ); - if ($exec_protect_test) { - $conf->data->set( has_exec_protect => 1 ); - } - else { - $conf->data->set( has_exec_protect => 0 ); - } - } - $conf->cc_clean(); - } - else { - $conf->data->set( has_exec_protect => 0 ); - } $self->set_result( 'yes' ); } else { - $conf->data->set( cc_build_call_frames => ''); + $conf->data->set(cc_build_call_frames => ''); $self->set_result( 'no' ); } return 1; diff --git a/config/auto/frames/test_exec_cygwin_c.in b/config/auto/frames/test_exec_cygwin_c.in deleted file mode 100644 index 4871d23..0000000 --- a/config/auto/frames/test_exec_cygwin_c.in +++ /dev/null @@ -1,76 +0,0 @@ -/* -Copyright (C) 2008-2009, Parrot Foundation. -$Id$ - -test for exec privs -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef PAGE_SIZE -# define PAGE_SIZE getpagesize() -#endif -# - -/* - * c equiv: - int t() { - return 1; -} -*/ - -char code[] = { - 0xB8, 0x01, 0, 0, 0, /* movl $1, %eax */ - 0xC3 /* ret */ -}; - -typedef int (*pf)(void); - -int -main(int argc, char *argv[]) -{ - pf t; - char *p; - int rc; - int prot = PROT_READ; - - if (argc != 2) { - fprintf(stderr, "usage: test 0 | 1\n"); - exit(1); - } - - if (atoi(argv[1])) - prot |= PROT_EXEC; - - p = memalign(PAGE_SIZE, PAGE_SIZE); - memcpy(p, code, sizeof (code)); - - t = (pf) p; - rc = mprotect(p, PAGE_SIZE, prot); - - if (rc) { - fprintf(stderr, "p = %p PAGE_SIZE = %d (0x%x)\n", p, - PAGE_SIZE, PAGE_SIZE); - perror("failure"); - } - - if (t() == 1) - puts("ok"); - else - return 1; - - return 0; -} - -/* - * Local variables: - * c-file-style: "parrot" - * End: - * vim: expandtab shiftwidth=4: - */ diff --git a/config/auto/frames/test_exec_linux_c.in b/config/auto/frames/test_exec_linux_c.in deleted file mode 100644 index 0090134..0000000 --- a/config/auto/frames/test_exec_linux_c.in +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright (C) 2004-2009, Parrot Foundation. -$Id$ - -test for exec privs - */ - -#include -#include -#include -#include -#include -#include -#include -#ifndef PAGE_SIZE -# define PAGE_SIZE getpagesize() -#endif - -/* - * c equiv: - int t() { - return 1; -} -*/ - -char code[] = { - 0xB8, 0x01, 0, 0, 0, /* movl $1, %eax */ - 0xC3 /* ret */ -}; - -typedef int (*pf)(void); - -int -main(int argc, char *argv[]) -{ - pf t; - char *p; - int rc; - int prot = PROT_READ; - - if (argc != 2) { - fprintf(stderr, "usage: test 0 | 1\n"); - exit(1); - } - if (atoi(argv[1])) - prot |= PROT_EXEC; - - p = memalign(PAGE_SIZE, sizeof (code)); - memcpy(p, code, sizeof (code)); - t = (pf) p; - rc = mprotect(p, PAGE_SIZE, prot); - if (rc) { - fprintf(stderr, "p = %p PAGE_SIZE = %d (0x%x)\n", p, - PAGE_SIZE, PAGE_SIZE); - perror("failure"); - } - - if (t() == 1) - puts("ok"); - else - return 1; - - return 0; -} - -/* - * Local variables: - * c-file-style: "parrot" - * End: - * vim: expandtab shiftwidth=4: - */ diff --git a/config/auto/frames/test_exec_openbsd_c.in b/config/auto/frames/test_exec_openbsd_c.in deleted file mode 100644 index 7f1826f..0000000 --- a/config/auto/frames/test_exec_openbsd_c.in +++ /dev/null @@ -1,71 +0,0 @@ -/* -Copyright (C) 2004-2009, Parrot Foundation. -$Id$ - -test for exec privs -*/ - -#include -#include -#include -#include -#include -#include -#include -#ifndef PAGE_SIZE -# define PAGE_SIZE sysconf(_SC_PAGESIZE) -#endif - -/* - * c equiv: - int t() { - return 1; -} -*/ - -char code[] = { - 0xB8, 0x01, 0, 0, 0, /* movl $1, %eax */ - 0xC3 /* ret */ -}; - -typedef int (*pf)(void); - -int -main(int argc, char *argv[]) -{ - pf t; - char *p; - int rc; - int prot = PROT_READ; - - if (argc != 2) { - fprintf(stderr, "usage: test 0 | 1\n"); - exit(1); - } - if (atoi(argv[1])) - prot |= PROT_EXEC; - - p = malloc(PAGE_SIZE); - memcpy(p, code, sizeof (code)); - t = (pf) p; - rc = mprotect(p, PAGE_SIZE, prot); - if (rc) { - fprintf(stderr, "p = %p PAGE_SIZE = %d (0x%x)\n", p, - PAGE_SIZE, PAGE_SIZE); - perror("failure"); - } - - if (t() == 1) - puts("ok"); - else - return 1; - - return 0; -} - -/* - * Local variables: - * c-file-style: "parrot" - * End: - * vim: expandtab shiftwidth=4: - */ diff --git a/config/auto/libjit.pm b/config/auto/libjit.pm new file mode 100644 index 0000000..9dca132 --- /dev/null +++ b/config/auto/libjit.pm @@ -0,0 +1,120 @@ +# Copyright (C) 2009, Parrot Foundation. +# $Id$ + +=head1 NAME + +config/auto/libjit - Check whether LibJIT is installed + +=head1 DESCRIPTION + +Determines whether libjit is present is installed and functional on the system. +It is OK when it doesn't exist. + +The libjit library implements just-in-time compilation functionality. Unlike +other JITs, this one is designed to be independent of any particular virtual +machine bytecode format or language. + +libjit can be obtained from L or through +your distribution's package manager. Developer documentation is available from +L + +=cut + +package auto::libjit; + +use strict; +use warnings; + +use base 'Parrot::Configure::Step'; + +use Parrot::Configure::Utils ':auto'; + +sub _init { + my $self = shift; + my %data = ( + description => 'Is LibJIT installed', + result => '', + ); + return \%data; +} + +sub runstep { + my ($self, $conf) = @_; + + my ($verbose, $without) = $conf->options->get( qw{ + verbose + without-libjit + }); + + my ($has_libjit, $extra_libs); + if ($without) { + $has_libjit = 0; + } + else { + $extra_libs = $self->_select_lib( { + conf => $conf, + osname => $conf->data->get_p5('OSNAME'), + cc => $conf->data->get('cc'), + win32_nongcc => 'libjit.lib', + default => '-ljit', + } ); + + $conf->cc_gen('config/auto/libjit/libjit_c.in'); + eval { $conf->cc_build('', $extra_libs) }; + if ($@) { + print "cc_build() failed: $@\n" if $verbose; + $has_libjit = 0; + } + else { + my $test; + eval { $test = $conf->cc_run(); }; + if ($@) { + print "cc_run() failed: $@\n" if $verbose; + $has_libjit = 0; + } + else { + $has_libjit = + $self->_evaluate_cc_run($test, $has_libjit, $verbose); + } + } + $conf->cc_clean(); + } + + $conf->data->set( HAS_LIBJIT => $has_libjit ); + _handle_has_libjit($conf, $has_libjit, $extra_libs); + $self->set_result( $has_libjit ? 'yes' : 'no' ); + + return 1; +} + +sub _evaluate_cc_run { + my ($self, $test, $has_libjit, $verbose) = @_; + if ($test =~ m/^USES INTERPRETER: \d+/ ) { + $has_libjit = 1; + print " (yes) " if $verbose; + $self->set_result("yes"); + } + return $has_libjit; +} + +sub _handle_has_libjit { + my ($conf, $has_libjit, $extra_libs) = @_; + if ($has_libjit) { + $conf->data->set( + libjit_has_alloca => ($conf->data->get('cpuarch') eq 'i386' ? '1' : '0'), + ); + $conf->data->add( ' ', libs => $extra_libs ); + } + else { + $conf->data->set( libjit_has_alloca => 0 ); + } +} + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/config/auto/libjit/libjit_c.in b/config/auto/libjit/libjit_c.in new file mode 100644 index 0000000..6875b92 --- /dev/null +++ b/config/auto/libjit/libjit_c.in @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009, Parrot Foundation. + * $Id$ + */ + +#include +#include +#include + +int +main(int argc, char *argv[]) { + jit_init(); + printf("USES INTERPRETER: %i\n", jit_uses_interpreter()); + return EXIT_SUCCESS; +} + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ diff --git a/config/gen/libjit.pm b/config/gen/libjit.pm new file mode 100644 index 0000000..12e3eaa --- /dev/null +++ b/config/gen/libjit.pm @@ -0,0 +1,258 @@ +# Copyright (C) 2009, Parrot Foundation. +# $Id$ + +=head1 NAME + +config/gen/libjit.pm - LibJIT Code Generation + +=head1 DESCRIPTION + +Populate F and +F with system appropriate +type information and automatically generated parrot function and +vtable jit wrappers. + +=cut + +package gen::libjit; + +use strict; +use warnings; + +use base 'Parrot::Configure::Step'; + +use Parrot::Configure::Utils ':gen'; + + +sub _init { + my $self = shift; + my %data = ( + description => 'Generate LibJIT specific code', + result => '', + targets => { + frame_builder_h => 'src/frame_builder_libjit.h', + frame_builder_c => 'src/frame_builder_libjit.c', + }, + templates => { + frame_builder_h => 'config/gen/libjit/frame_builder_libjit_h.in', + frame_builder_c => 'config/gen/libjit/frame_builder_libjit_c.in', + }, + wrapped_vtables => { + get_integer => [ () => 'INTVAL' ], + set_integer_native => [ ('INTVAL') => 'void' ], + get_pointer => [ () => 'void_ptr' ], + set_pointer => [ ('void_ptr') => 'void' ], + get_string_keyed_int => [ ('INTVAL') => 'void_ptr' ], + }, + wrapped_funcs => { + Parrot_pcc_fill_params_from_c_args => + [ qw(void_ptr void_ptr void_ptr ...) => 'void' ], + Parrot_pcc_fill_returns_from_c_args => + [ qw(void_ptr void_ptr void_ptr ...) => 'void' ], + + Parrot_str_new => + [ qw(void_ptr void_ptr UINTVAL) => 'void_ptr' ], + Parrot_str_to_cstring => + [ qw(void_ptr void_ptr) => 'void_ptr' ], + Parrot_str_free_cstring => + [ ('void_ptr') => 'void' ], + + pmc_new_noinit => + [ qw(void_ptr INTVAL) => 'void_ptr' ], + + mem_sys_allocate => [ ('long') => 'void_ptr' ], + mem_sys_free => [ ('void_ptr') => 'void' ], + }, + ); + return \%data; +} + +sub runstep { + my ($self, $conf) = @_; + + my ($libjit_iv, $libjit_uv) = @{ + my $iv = $conf->data->get('iv') || ''; + { + short => [ 'jit_type_sys_short' , 'jit_type_sys_ushort' ], + int => [ 'jit_type_sys_int' , 'jit_type_sys_uint' ], + long => [ 'jit_type_sys_long' , 'jit_type_sys_ulong' ], + 'long long' => [ 'jit_type_sys_longlong', 'jit_type_sys_ulonglong' ], + }->{$iv} + or die "Couldn't determine libjity type for intval of type '$iv'"; + }; + + my $libjit_nv = do { + my $nv = $conf->data->get('nv') || ''; + { + float => 'jit_type_sys_float', + double => 'jit_type_sys_double', + 'long double' => 'jit_type_sys_long_double', + }->{$nv} + or die "Couldn't determine libjity type for floatval of type '$nv'"; + }; + + $conf->data->set( libjit_iv => $libjit_iv, + libjit_uv => $libjit_uv, + libjit_nv => $libjit_nv, ); + + my @vtable_wrappers = + map {gen_vtable_wrapper($self, $_)} keys %{$self->{wrapped_vtables}}; + my @function_wrappers = + map {gen_function_wrapper($self, $_)} keys %{$self->{wrapped_funcs}}; + + $conf->data->set( + TEMP_vtable_wrap_decls => + (join "\n", map {$_->{decl}} @vtable_wrappers), + TEMP_vtable_wrap_defns => + (join "\n", map {$_->{defn}} @vtable_wrappers), + TEMP_func_wrap_decls => + (join "\n", map {$_->{decl}} @function_wrappers), + TEMP_func_wrap_defns => + (join "\n", map {$_->{defn}} @function_wrappers) + ); + + foreach my $t (keys %{$self->{targets}}) { + $conf->genfile($self->{templates}{$t}, $self->{targets}{$t}); + $conf->append_configure_log($t); + } + + return 1; +} + +sub gen_vtable_wrapper { + my ($self, $entry_name) = @_; + + my $entry_sig = $self->{wrapped_vtables}{$entry_name}; + $_ = jit_prefix_type($_) for @$entry_sig; + + my $ret_t = pop @$entry_sig; + my $arg_t = join ", ", @$entry_sig; + + my $n_args = scalar @$entry_sig; + my $arg_decls_t = join ", ", map {'jit_value_t'} 1..$n_args; + my $arg_decls_v = join ", ", map {"jit_value_t v$_"} 1..$n_args; + my $arg_v = join ", ", map {"v$_"} 1..$n_args; + + my $_arg_decls_t = $n_args ? ", $arg_decls_t" : ""; + my $_arg_decls_v = $n_args ? ", $arg_decls_v" : ""; + my $_arg_t = $n_args ? ", $arg_t" : ""; + my $_arg_v = $n_args ? ", $arg_v" : ""; + + return { decl => < <{wrapped_funcs}{$func_name}; + $_ = jit_prefix_type($_) for @$func_sig; + + my $ret_t = pop @$func_sig; + + my $vararg = 0; + if ($func_sig->[-1] eq '...') { + $vararg = 1; + pop @$func_sig; + } + + my $arg_t = join ", ", @$func_sig; + + my $n_args = scalar @$func_sig; + my $arg_decls_t = join ", ", map {'jit_value_t'} 1..$n_args; + my $arg_decls_v = join ", ", map {"jit_value_t v$_"} 1..$n_args; + my $arg_v = join ", ", map {"v$_"} 1..$n_args; + + my ($decl, $defn); + if ($vararg) { + $decl = < $decl, defn => $defn }; +} + +sub jit_prefix_type { + my $type = shift; + if ($type =~ /^[_a-z]+$/) { + return "jit_type_$type"; + } + elsif ($type =~ /^[_A-Z]+$/) { + return "JIT_TYPE_$type"; + } + else { + return $type; + } +} + +1; + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/config/gen/libjit/frame_builder_libjit_c.in b/config/gen/libjit/frame_builder_libjit_c.in new file mode 100644 index 0000000..a312959 --- /dev/null +++ b/config/gen/libjit/frame_builder_libjit_c.in @@ -0,0 +1,655 @@ +/* +Copyright (C) 2008-2009, Parrot Foundation. +$Id$ +*/ + +/* HEADERIZER HFILE: none */ +/* HEADERIZER STOP */ + +#include "parrot/parrot.h" +#include "pmc/pmc_context.h" +#include "pmc/pmc_integer.h" +#include "pmc/pmc_managedstruct.h" +#include "pmc/pmc_unmanagedstruct.h" +#include "frame_builder.h" +#include "frame_builder_libjit.h" + +#ifdef PARROT_HAS_LIBJIT + +/* + +=over 4 + +=item C + +Public interface to NCI function interface builder. + +=cut + +*/ + +void * +Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc, STRING *sig, void **priv) { + void *thunk; + char *sig_cstr; + + sig_cstr = Parrot_str_to_cstring(interp, sig); + *priv = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); + + thunk = Parrot_jit_create_thunk(interp, sig_cstr, *priv); + + Parrot_str_free_cstring(sig_cstr); + + return thunk; +} + +/* + +=item C + +This is a callback to implement the proper freeing semantics. It is called by +the ManagedStruct PMC as it is garbage collected. + +=cut + +*/ + +void +Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv) +{ + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + jit_context_destroy(jit->ctx); + mem_sys_free(jit->sig); + mem_sys_free(priv); +} + +/* + +=item C + +This is a callback to implement the proper cloning semantics for jit buffers. +It is called by the ManagedStruct PMC's clone() function. + +=back + +=cut + +*/ + +PMC * +Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv) +{ + PMC * const rv = pmc_new(interp, pmc->vtable->base_type); + + VTABLE_init(interp, rv); + /* copy the attributes */ + { + void (*tmpfreefunc)(PARROT_INTERP, void*, void*); + GETATTR_ManagedStruct_custom_free_func(interp, pmc, tmpfreefunc); + SETATTR_ManagedStruct_custom_free_func(interp, rv , tmpfreefunc); + } + { + PMC* (*tmpclonefunc)(PARROT_INTERP, PMC*, void*); + GETATTR_ManagedStruct_custom_clone_func(interp, pmc, tmpclonefunc); + SETATTR_ManagedStruct_custom_clone_func(interp, rv , tmpclonefunc); + } + + /* compile a clone of the function */ + if (PARROT_MANAGEDSTRUCT(pmc)->ptr) { + void *rv_priv; + struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; + STRING *sig = Parrot_str_new(interp, jit->sig, 0); + PARROT_MANAGEDSTRUCT(rv)->ptr = Parrot_jit_build_call_func(interp, rv, sig, &rv_priv); + } + + return rv; +} + +/* + * JIT functions + */ + +static void * +Parrot_jit_create_thunk(PARROT_INTERP, char *sig, void *priv) { + struct jit_buffer_private_data *p; + jit_function_t f; + jit_value_t jit_interp, jit_nci_pmc, jit_pcc_sig; + jit_value_t jit_func, jit_pcc_sig_args, jit_pcc_sig_ret; + jit_value_t jit_call_object; + + /* populate private data */ + p = (struct jit_buffer_private_data*)priv; + p->ctx = jit_context_create(); + p->sig = mem_sys_strdup(sig); + + /* start compiling */ + jit_context_build_start(p->ctx); + + /* start JIT function */ + { + jit_type_t arg_types[] = { + jit_type_void_ptr, /* interp */ + jit_type_void_ptr, /* nci_pmc */ + }; + jit_type_t f_sig = jit_type_create_signature(jit_abi_cdecl, jit_type_void, arg_types, 2, 1); + f = jit_function_create(p->ctx, f_sig); + } + + /* get the incomming args */ + jit_interp = jit_value_get_param(f, 0); + jit_nci_pmc = jit_value_get_param(f, 1); + + /* get information out of the NCI object */ + jit_func = jit__vtable_get_pointer(f, jit_interp, jit_nci_pmc); + { + jit_value_t temp = jit__vtable_get_string_keyed_int(f, jit_interp, jit_nci_pmc, + jit_value_create_nint_constant(f, JIT_TYPE_INTVAL, PARROT_NCI_PCC_SIGNATURE_PARAMS)); + jit_pcc_sig_args = jit__Parrot_str_to_cstring(f, jit_interp, temp); + } + { + jit_value_t temp = jit__vtable_get_string_keyed_int(f, jit_interp, jit_nci_pmc, + jit_value_create_nint_constant(f, JIT_TYPE_INTVAL, PARROT_NCI_PCC_SIGNATURE_RET)); + jit_pcc_sig_ret = jit__Parrot_str_to_cstring(f, jit_interp, temp); + } + + /* get call_object */ + { + jit_value_t ctx = jit__CURRENT_CONTEXT(f, jit_interp); + jit_call_object = jit__Parrot_pcc_get_signature(f, jit_interp, ctx); + } + + /* get the outgoing args */ + { + int nargs = strlen(sig) - 1; + + jit_type_t jit_args_t[nargs]; + jit_value_t jit_args_v[nargs]; + jit_value_t jit_regs[nargs]; + + Parrot_jit_parse_sig_args_pre(interp, sig, nargs, f, jit_interp, jit_call_object, jit_pcc_sig_args, + jit_args_t, jit_args_v, jit_regs); + + /* get the return type */ + { + jit_type_t ret_t; + jit_value_t ret_v; + + ret_t = Parrot_jit_parse_sig_ret_pre(interp, sig); + + /* make the call */ + { + jit_type_t jit_sig + = jit_type_create_signature(jit_abi_cdecl, ret_t, jit_args_t, nargs, 1); + ret_v = jit_insn_call_indirect(f, jit_func, jit_sig, jit_args_v, nargs, 0); + } + + /* get the incomming return */ + Parrot_jit_parse_sig_ret_post(interp, sig, f, jit_interp, jit_call_object, jit_pcc_sig_ret, ret_v); + } + + /* clean up args */ + Parrot_jit_parse_sig_args_post(interp, sig, nargs, f, jit_interp, jit_args_v, jit_regs); + } + + /* free PCC signature bits */ + jit__Parrot_str_free_cstring(f, jit_pcc_sig_args); + jit__Parrot_str_free_cstring(f, jit_pcc_sig_ret); + + /* end JIT function */ + jit_insn_return(f, NULL); + + /* compile to native callable func poitner */ + jit_function_compile(f); + jit_context_build_end(p->ctx); + + return jit_function_to_closure(f); +} + +static int +Parrot_jit_create_arg_regs(PARROT_INTERP, char *sig, int nargs, + jit_function_t f, jit_value_t *reg_v) { + int i, j; + for (i = 0, j = 0; i < nargs; i++) { + char c; + switch (c = sig[i]) { + case 'I': + case 'c': + case 's': + case 'i': + case 'l': + reg_v[j++] = jit_value_create(f, JIT_TYPE_INTVAL); + break; + + case 'N': + case 'd': + case 'f': + reg_v[j++] = jit_value_create(f, JIT_TYPE_FLOATVAL); + break; + + case 'S': + case 'B': + case 'b': + case 't': + reg_v[j++] = jit_value_create(f, jit_type_void_ptr); + break; + + case 'p': + case 'P': + case 'O': + case '@': + case '2': + case '3': + case '4': + case 'V': + reg_v[j++] = jit_value_create(f, jit_type_void_ptr); + break; + + default: + /* don't catch errors here; fail elsewhere */ + break; + } + } + + return j; +} + +static void +Parrot_jit_fill_args(PARROT_INTERP, char *sig, int nargs, int nregs, + jit_function_t f, jit_value_t jit_interp, jit_value_t call_object, jit_value_t jit_pcc_sig_args, + jit_value_t *reg_v, jit_type_t *arg_t, jit_value_t *arg_v) { + int i, j; + + /* fill argument registers */ + { + jit_type_t jit_reg_addr_t[nregs]; + jit_value_t jit_reg_addr_v[nregs]; + for (i = 0; i < nregs; i++) { + jit_reg_addr_t[i] = jit_type_void_ptr; + jit_value_set_addressable(reg_v[i]); + jit_reg_addr_v[i] = jit_insn_address_of(f, reg_v[i]); + } + jit__Parrot_pcc_fill_params_from_c_args(f, jit_interp, call_object, jit_pcc_sig_args, + jit_reg_addr_t, jit_reg_addr_v, nregs); + } + + for (i = 0, j = 0; i < nargs; i++) { + char c; + jit_type_t t1; + jit_label_t l1; + jit_value_t v1, v2, v3, v4; + switch (c = sig[i]) { + case 'I': + t1 = JIT_TYPE_INTVAL; + goto pop_reg; + case 'c': + t1 = jit_type_sys_char; + goto pop_reg; + case 's': + t1 = jit_type_sys_short; + goto pop_reg; + case 'i': + t1 = jit_type_sys_int; + goto pop_reg; + case 'l': + t1 = jit_type_sys_long; + goto pop_reg; + case 'N': + t1 = JIT_TYPE_FLOATVAL; + goto pop_reg; + case 'f': + t1 = jit_type_sys_float; + goto pop_reg; + case 'd': + t1 = jit_type_sys_double; + goto pop_reg; + case 'S': + case 'P': + case 'O': + case '@': + t1 = jit_type_void_ptr; + pop_reg: + arg_t[i] = t1; + arg_v[i] = jit_value_create(f, t1); + jit_insn_store(f, arg_v[i], reg_v[j]); + j++; + break; + + case 't': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit_value_create(f, jit_type_void_ptr); + jit_insn_store(f, arg_v[i], + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)); + v1 = jit_insn_eq(f, reg_v[j], + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)); + l1 = jit_label_undefined; + jit_insn_branch_if(f, v1, &l1); + jit_insn_store(f, arg_v[i], jit__Parrot_str_to_cstring(f, jit_interp, reg_v[j])); + jit_insn_label(f, &l1); + + j++; + break; + + case 'b': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit__Buffer_bufstart(f, reg_v[j]); + j++; + break; + + case 'B': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit_value_create(f, jit_type_void_ptr); + jit_insn_store(f, arg_v[i], + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)); + v1 = jit_insn_eq(f, reg_v[j], + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)); + l1 = jit_label_undefined; + jit_insn_branch_if(f, v1, &l1); + v2 = jit__Parrot_str_to_cstring(f, jit_interp, reg_v[j]); + v3 = jit_value_create(f, jit_type_void_ptr); + jit_value_set_addressable(v3); + jit_insn_store(f, v3, v2); + jit_insn_store(f, arg_v[i], jit_insn_address_of(f, v3)); + jit_insn_label(f, &l1); + j++; + break; + + case 'p': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit_value_create(f, jit_type_void_ptr); + jit_insn_store(f, arg_v[i], + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)); + v1 = jit__PMC_IS_NULL(f, reg_v[j]); + l1 = jit_label_undefined; + jit_insn_branch_if(f, v1, &l1); + v2 = jit__vtable_get_pointer(f, jit_interp, reg_v[j]); + jit_insn_store(f, arg_v[i], v2); + jit_insn_label(f, &l1); + j++; + break; + + case '2': + t1 = jit_type_sys_short; + goto call_get_integer; + case '3': + t1 = jit_type_sys_int; + goto call_get_integer; + case '4': + t1 = jit_type_sys_long; + call_get_integer: + arg_t[i] = jit_type_void_ptr; + v1 = jit__vtable_get_integer(f, jit_interp, reg_v[j]); + v2 = jit_value_create(f, t1); + jit_value_set_addressable(v2); + jit_insn_store(f, v2, v1); + arg_v[i] = jit_insn_address_of(f, v2); + j++; + break; + + case 'V': + arg_t[i] = jit_type_void_ptr; + v1 = jit__vtable_get_pointer(f, jit_interp, reg_v[j]); + v2 = jit_value_create(f, jit_type_void_ptr); + jit_value_set_addressable(v2); + jit_insn_store(f, v2, v1); + arg_v[i] = jit_insn_address_of(f, v2); + j++; + break; + + case '0': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL); + break; + + case 'J': + arg_t[i] = jit_type_void_ptr; + arg_v[i] = jit_interp; + break; + + default: + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "unkown arg type '%c'", c); + return; + } + } +} + +static void +Parrot_jit_parse_sig_args_pre(PARROT_INTERP, char *sig, int nargs, + jit_function_t f, jit_value_t jit_interp, jit_value_t call_object, jit_value_t jit_pcc_sig_args, + jit_type_t *jit_args_t, + jit_value_t *jit_args_v, jit_value_t *jit_regs_v) { + int nregs; + + sig += 1; /* ignore return character */ + + nregs = Parrot_jit_create_arg_regs(interp, sig, nargs, f, jit_regs_v); + Parrot_jit_fill_args(interp, sig, nargs, nregs, f, jit_interp, call_object, jit_pcc_sig_args, + jit_regs_v, jit_args_t, jit_args_v); +} + +static jit_type_t +Parrot_jit_parse_sig_ret_pre(PARROT_INTERP, char *sig) { + char c; + switch (c = sig[0]) { + case 'v': + return jit_type_void; + + case 'I': + return JIT_TYPE_INTVAL; + case 'c': + return jit_type_sys_char; + case 's': + return jit_type_sys_short; + case 'i': + return jit_type_sys_int; + case 'l': + return jit_type_sys_long; + + case 'N': + return JIT_TYPE_FLOATVAL; + case 'f': + return jit_type_sys_float; + case 'd': + return jit_type_sys_double; + + case 'S': + case 't': + return jit_type_void_ptr; + + case 'p': + case 'P': + return jit_type_void_ptr; + + default: + /* FAIL */ + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, + "unknown return type '%c'", c); + return NULL; + } +} + +static void +Parrot_jit_parse_sig_ret_post(PARROT_INTERP, char *sig, + jit_function_t f, jit_value_t jit_interp, jit_value_t call_object, + jit_value_t pcc_sig, jit_value_t retval) { + jit_type_t ret_t[1]; + jit_value_t ret_v[1]; + + jit_type_t t1; + jit_value_t v1, v2, v3; + switch (sig[0]) { + case 'v': + break; + + case 'I': + case 'c': + case 's': + case 'i': + case 'l': + ret_t[0] = JIT_TYPE_INTVAL; + goto fill_ret; + case 'N': + case 'f': + case 'd': + ret_t[0] = JIT_TYPE_FLOATVAL; + goto fill_ret; + case 'S': + case 'P': + ret_t[0] = jit_type_void_ptr; + goto fill_ret; + case 't': + ret_t[0] = jit_type_void_ptr; + retval = jit__Parrot_str_new(f, jit_interp, retval, + jit_value_create_nint_constant(f, jit_type_sys_int, 0)); + goto fill_ret; + case 'p': + ret_t[0] = jit_type_void_ptr; + v1 = jit__pmc_new_noinit(f, jit_interp, + jit_value_create_intval_constant(f, enum_class_UnManagedStruct)); + jit__vtable_set_pointer(f, jit_interp, v1, retval); + retval = v1; + goto fill_ret; + case '2': + t1 = jit_type_sys_short; + goto create_int_pmc; + case '3': + t1 = jit_type_sys_int; + goto create_int_pmc; + case '4': + t1 = jit_type_sys_long; + create_int_pmc: + ret_t[0] = jit_type_void_ptr; + v1 = jit_insn_load_relative(f, retval, 0, t1); + v2 = jit__pmc_new_noinit(f, jit_interp, + jit_value_create_intval_constant(f, enum_class_Integer)); + jit__vtable_set_integer_native(f, jit_interp, v2, v1); + retval = v2; + fill_ret: + ret_v[0] = jit_value_create(f, ret_t[0]); + jit_insn_store(f, ret_v[0], retval); + jit__Parrot_pcc_fill_returns_from_c_args(f, jit_interp, call_object, pcc_sig, ret_t, ret_v, 1); + break; + + default: + /* ignore (failed elsewhere) */ + break; + } +} + +static void +Parrot_jit_parse_sig_args_post(PARROT_INTERP, char *sig, int nargs, + jit_function_t f, jit_value_t jit_interp, + jit_value_t *args, jit_value_t *regs) { + int i, j; + + sig += 1; + + for (i = 0, j = 0; i < nargs; i++) { + jit_type_t t1; + jit_value_t v1; + switch (sig[i]) { + case 't': + jit__Parrot_str_free_cstring(f, args[i]); + j++; + break; + + case 'B': + v1 = jit_insn_load_relative(f, args[i], 0, jit_type_void_ptr); + jit__Parrot_str_free_cstring(f, v1); + j++; + break; + + case '2': + t1 = jit_type_sys_short; + goto set_integer; + case '3': + t1 = jit_type_sys_int; + goto set_integer; + case '4': + t1 = jit_type_sys_long; + set_integer: + v1 = jit_insn_load_relative(f, args[i], 0, t1); + jit__vtable_set_integer_native(f, jit_interp, regs[j], v1); + j++; + break; + + case 'V': + v1 = jit_insn_load_relative(f, args[i], 0, jit_type_void_ptr); + jit__vtable_set_pointer(f, jit_interp, regs[j], v1); + j++; + break; + + case 'I': + case 'c': + case 'i': + case 'l': + case 'N': + case 'f': + case 'd': + case 'S': + case 'b': + case 'p': + case 'P': + case 'O': + case '@': + j++; + break; + + default: + /* ignore */ + break; + } + } +} + +static jit_value_t +jit_value_create_intval_constant(jit_function_t f, INTVAL i) { + return jit_value_create_nint_constant(f, JIT_TYPE_INTVAL, i); +} + +/* + * JIT wrappers + */ + +/* custom wrappers */ +static jit_value_t +jit__Buffer_bufstart(jit_function_t f, jit_value_t buf) { + return jit_insn_load_relative(f, buf, offsetof(Buffer, _bufstart), jit_type_void_ptr); +} + +static jit_value_t +jit__CURRENT_CONTEXT(jit_function_t f, jit_value_t interp) { + return jit_insn_load_relative(f, interp, offsetof(struct parrot_interp_t, ctx), jit_type_void_ptr); +} + +static jit_value_t +jit__PMC_IS_NULL(jit_function_t f, jit_value_t pmc) { + return jit_insn_or(f, + jit_insn_eq(f, pmc, + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)NULL)), + jit_insn_eq(f, pmc, + jit_value_create_nint_constant(f, jit_type_void_ptr, (jit_nint)PMCNULL))); +} + +static jit_value_t +jit__Parrot_pcc_get_signature(jit_function_t f, jit_value_t interp, jit_value_t ctx) { + return jit_insn_load_relative(f, + jit_insn_load_relative(f, ctx, offsetof(struct PMC, data), jit_type_void_ptr), + offsetof(struct Parrot_Context_attributes, current_sig), + jit_type_void_ptr); +} + +/* vtable wrappers */ +@TEMP_vtable_wrap_defns@ + +/* function wrappers */ +@TEMP_func_wrap_defns@ + +#endif /* PARROT_HAS_LIBJIT */ + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ diff --git a/config/gen/libjit/frame_builder_libjit_h.in b/config/gen/libjit/frame_builder_libjit_h.in new file mode 100644 index 0000000..b77039a --- /dev/null +++ b/config/gen/libjit/frame_builder_libjit_h.in @@ -0,0 +1,112 @@ +/* frame_builder_libjit.h + * $Id$ + * Copyright (C) 2009, Parrot Foundation. + */ + +#ifndef PARROT_FRAME_BUILDER_LIBJIT_H_GUARD +#define PARROT_FRAME_BUILDER_LIBJIT_H_GUARD + + +#if defined(__cplusplus) +# define EXTERN extern "C" +#else +# define EXTERN +#endif + +#include +#include "parrot/parrot.h" +#include "frame_builder.h" + +#ifdef PARROT_HAS_LIBJIT + +# include + +/* + * JITted function state data + */ +struct jit_buffer_private_data { + jit_context_t ctx; + char *sig; +}; + +/* + * JIT types + */ + +# define JIT_TYPE_UINTVAL @libjit_uv@ +# define JIT_TYPE_INTVAL @libjit_iv@ +# define JIT_TYPE_FLOATVAL @libjit_nv@ + +/* + * JIT functions + */ + +static void * +Parrot_jit_create_thunk(Interp *, char *, void *); + +static void +Parrot_jit_parse_sig_args_pre(Interp *, char *, int, jit_function_t, jit_value_t, jit_value_t, jit_value_t, + jit_type_t *, jit_value_t *, jit_value_t *); + +static jit_type_t +Parrot_jit_parse_sig_ret_pre(Interp *, char *); + +static void +Parrot_jit_parse_sig_ret_post(Interp *, char *, jit_function_t, jit_value_t, jit_value_t, jit_value_t, jit_value_t); + +static void +Parrot_jit_parse_sig_args_post(Interp *, char *, int, jit_function_t, jit_value_t, jit_value_t *, jit_value_t *); + +static int +Parrot_jit_create_arg_regs(Interp *, char *, int, jit_function_t, jit_value_t *); + +static void +Parrot_jit_fill_args(Interp *, char *, int, int, jit_function_t, jit_value_t, jit_value_t, jit_value_t, + jit_value_t *, jit_type_t *, jit_value_t *); + +static jit_value_t +jit_value_create_intval_constant(jit_function_t, INTVAL); + +/* + * workaround for platforms that lack libjit alloca support + */ +# if @libjit_has_alloca@ +# define JIT_ALLOCA(f, n) jit_insn_alloca((f), (n)) +# define JIT_ALLOCA_FREE(f, p) +# else +# define JIT_ALLOCA(f, n) jit__mem_sys_allocate((f), (n)) +# define JIT_ALLOCA_FREE(f, p) jit__mem_sys_free((f), (p)) +# endif + +/* + * JIT wrappers + */ + +/* custom wrappers */ +static jit_value_t +jit__Buffer_bufstart(jit_function_t, jit_value_t); + +static jit_value_t +jit__CURRENT_CONTEXT(jit_function_t, jit_value_t); + +static jit_value_t +jit__PMC_IS_NULL(jit_function_t, jit_value_t); + +static jit_value_t +jit__Parrot_pcc_get_signature(jit_function_t, jit_value_t, jit_value_t); + +/* vtable wrappers */ +@TEMP_vtable_wrap_decls@ + +/* function wrappers */ +@TEMP_func_wrap_decls@ + +#endif /* PARROT_HAS_LIBJIT */ +#endif /* PARROT_FRAME_BUILDER_LIBJIT_H_GUARD */ + +/* + * Local variables: + * c-file-style: "parrot" + * End: + * vim: expandtab shiftwidth=4: + */ diff --git a/config/gen/makefiles/root.in b/config/gen/makefiles/root.in index 0519f7d..0f54a72 100644 --- a/config/gen/makefiles/root.in +++ b/config/gen/makefiles/root.in @@ -217,6 +217,8 @@ CONFIGURE_GENERATED_FILES := \ myconfig \ $(GEN_PASM_INCLUDES) \ $(SRC_DIR)/call_list.txt \ + $(SRC_DIR)/frame_builder_libjit.h \ + $(SRC_DIR)/frame_builder_libjit.c \ MANIFEST.configure.generated \ .configure_trace.sto \ .parrot_current_rev @@ -441,7 +443,7 @@ INTERP_O_FILES := \ $(SRC_DIR)/longopt$(O) \ $(SRC_DIR)/misc$(O) \ $(SRC_DIR)/multidispatch$(O) \ - $(SRC_DIR)/frame_builder$(O) \ + $(SRC_DIR)/frame_builder_libjit$(O) \ $(SRC_DIR)/nci$(O) \ $(SRC_DIR)/oo$(O) \ $(SRC_DIR)/packfile$(O) \ @@ -624,7 +626,7 @@ STR_FILES := \ $(SRC_DIR)/key.str \ $(SRC_DIR)/library.str \ $(SRC_DIR)/multidispatch.str \ - $(SRC_DIR)/frame_builder.str \ + $(SRC_DIR)/frame_builder_libjit.str \ $(SRC_DIR)/nci.str \ $(SRC_DIR)/packfile.str \ $(SRC_DIR)/pmc.str \ @@ -1200,13 +1202,17 @@ $(SRC_DIR)/dataypes$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/dataypes.c $(SRC_DIR)/exit$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/exit.c $(SRC_DIR)/nci$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/nci.c $(SRC_DIR)/nci.str \ - $(SRC_DIR)/frame_builder$(O) \ - $(SRC_DIR)/pmc/pmc_unmanagedstruct.h \ + $(SRC_DIR)/frame_builder_libjit$(O) \ $(SRC_DIR)/pmc/pmc_managedstruct.h \ $(SRC_DIR)/pmc/pmc_nci.h \ $(SRC_DIR)/pmc/pmc_pointer.h -$(SRC_DIR)/frame_builder$(O) : $(SRC_DIR)/frame_builder.h $(GENERAL_H_FILES) $(SRC_DIR)/frame_builder.c $(SRC_DIR)/frame_builder.str +$(SRC_DIR)/frame_builder_libjit$(O) : \ + $(SRC_DIR)/frame_builder_libjit.h \ + $(SRC_DIR)/frame_builder_libjit.c \ + $(SRC_DIR)/frame_builder_libjit.str \ + $(SRC_DIR)/frame_builder.h \ + $(GENERAL_H_FILES) $(SRC_DIR)/vtables$(O) : $(GENERAL_H_FILES) $(SRC_DIR)/vtables.c diff --git a/config/gen/parrot_include.pm b/config/gen/parrot_include.pm index 58dcb5d..b89d14b 100644 --- a/config/gen/parrot_include.pm +++ b/config/gen/parrot_include.pm @@ -39,13 +39,13 @@ sub _init { include/parrot/library.h include/parrot/longopt.h include/parrot/multidispatch.h + include/parrot/nci.h include/parrot/packfile.h include/parrot/stat.h include/parrot/string.h include/parrot/pmc.h include/parrot/warnings.h include/parrot/gc_api.h - src/pmc/timer.pmc src/utils.c ) ]; $data{generated_files} = [ qw( diff --git a/include/parrot/nci.h b/include/parrot/nci.h index 1ff85c4..86ad460 100644 --- a/include/parrot/nci.h +++ b/include/parrot/nci.h @@ -15,6 +15,17 @@ #include "parrot/parrot.h" +/* NCI PMC interface constants */ +/* &gen_from_enum(nci.pasm) */ +typedef enum { + PARROT_NCI_ARITY, + PARROT_NCI_PCC_SIGNATURE_PARAMS, + PARROT_NCI_PCC_SIGNATURE_RET, + PARROT_NCI_LONG_SIGNATURE, + PARROT_NCI_MULTI_SIG, +} parrot_nci_enum_t; +/* &end_gen */ + void *build_call_func(PARROT_INTERP, SHIM(PMC *pmc_nci), NOTNULL(STRING *signature), NOTNULL(int *jitted)); #endif /* PARROT_NCI_H_GUARD */ diff --git a/lib/Parrot/Configure/Options/Conf.pm b/lib/Parrot/Configure/Options/Conf.pm index 27ca853..497d3b9 100644 --- a/lib/Parrot/Configure/Options/Conf.pm +++ b/lib/Parrot/Configure/Options/Conf.pm @@ -105,6 +105,7 @@ External Library Options: --without-gmp Build parrot without GMP support --without-opengl Build parrot without OpenGL support (GL/GLU/GLUT) --without-pcre Build parrot without pcre support + --without-libjit Build parrot without LibJIT support ICU Options: diff --git a/lib/Parrot/Configure/Options/Conf/Shared.pm b/lib/Parrot/Configure/Options/Conf/Shared.pm index 729923e..f8dd3ea 100644 --- a/lib/Parrot/Configure/Options/Conf/Shared.pm +++ b/lib/Parrot/Configure/Options/Conf/Shared.pm @@ -75,6 +75,7 @@ our @shared_valid_options = qw{ without-gettext without-gmp without-icu + without-libjit without-opengl without-pcre without-threads diff --git a/lib/Parrot/Configure/Step/List.pm b/lib/Parrot/Configure/Step/List.pm index 0b2190a..1989254 100644 --- a/lib/Parrot/Configure/Step/List.pm +++ b/lib/Parrot/Configure/Step/List.pm @@ -39,6 +39,7 @@ my @steps = qw( auto::format auto::isreg auto::arch + auto::libjit auto::jit auto::frames auto::cpu @@ -70,11 +71,16 @@ my @steps = qw( gen::parrot_include gen::opengl gen::call_list + gen::libjit gen::makefiles gen::platform gen::config_pm ); +=pod + +=cut + sub get_steps_list { return @steps; } 1; diff --git a/lib/Parrot/Distribution.pm b/lib/Parrot/Distribution.pm index 9c668b9..7b48377 100644 --- a/lib/Parrot/Distribution.pm +++ b/lib/Parrot/Distribution.pm @@ -433,6 +433,8 @@ This is to exclude automatically generated C-language files Parrot might have. include/parrot/config.h include/parrot/has_header.h src/gc/malloc.c + src/frame_builder_libjit.h + src/frame_builder_libjit.c } unless @exemptions; my $path = -f $file ? $file : $file->path; diff --git a/lib/Parrot/NativeCall.pm b/lib/Parrot/NativeCall.pm new file mode 100644 index 0000000..d0145f8 --- /dev/null +++ b/lib/Parrot/NativeCall.pm @@ -0,0 +1,128 @@ +# Copyright (C) 2009, Parrot Foundation. +# $Id$ + +package Parrot::NativeCall; + +use strict; +use warnings; + +use base 'Exporter'; +our @EXPORT_OK = qw{ signature_nci_to_pcc }; + +=head1 NAME + +Parrot::NativeCall - Tools for building native call routines + +=head1 SYNOPSIS + + use Parrot::NativeCall 'signature_nci_to_pcc'; + + my $pcc_sig = signature_nci_to_pcc("v VVV"); + +=head1 DESCRIPTION + +C knows how to map NCI signatures to nci frame +functions. + +=head1 GLOBAL VARIABLES + +=over + +=item C<%signature_table> + +Maps NCI signature items to elements of a native call routine. + +For use by F. New code should probably write +a wrapper in this module to encapsulate the access. + +=cut + +our %signature_table = ( + p => { + as_proto => "void *", + other_decl => "PMC * const final_destination = pmc_new(interp, enum_class_UnManagedStruct);", + sig_char => "P", + ret_assign => "VTABLE_set_pointer(interp, final_destination, return_data);\n Parrot_pcc_fill_returns_from_c_args(interp, call_object, \"P\", final_destination);", + }, + i => { as_proto => "int", sig_char => "I" }, + l => { as_proto => "long", sig_char => "I" }, + c => { as_proto => "char", sig_char => "I" }, + s => { as_proto => "short", sig_char => "I" }, + f => { as_proto => "float", sig_char => "N" }, + d => { as_proto => "double", sig_char => "N" }, + t => { as_proto => "char *", + other_decl => "STRING *final_destination;", + ret_assign => "final_destination = Parrot_str_new(interp, return_data, 0);\n Parrot_pcc_fill_returns_from_c_args(interp, call_object, \"S\", final_destination);", + sig_char => "S" }, + v => { as_proto => "void", + return_type => "void *", + sig_char => "v", + ret_assign => "", + func_call_assign => "" + }, + P => { as_proto => "PMC *", sig_char => "P" }, + O => { as_proto => "PMC *", returns => "", sig_char => "Pi" }, + J => { as_proto => "PARROT_INTERP", returns => "", sig_char => "" }, + S => { as_proto => "STRING *", sig_char => "S" }, + I => { as_proto => "INTVAL", sig_char => "I" }, + N => { as_proto => "FLOATVAL", sig_char => "N" }, + b => { as_proto => "void *", as_return => "", sig_char => "S" }, + B => { as_proto => "char **", as_return => "", sig_char => "S" }, + # These should be replaced by modifiers in the future + 2 => { as_proto => "short *", sig_char => "P", return_type => "short", + ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, + 3 => { as_proto => "int *", sig_char => "P", return_type => "int", + ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, + 4 => { as_proto => "long *", sig_char => "P", return_type => "long", + ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, + L => { as_proto => "long *", as_return => "" }, + T => { as_proto => "char **", as_return => "" }, + V => { as_proto => "void **", as_return => "", sig_char => "P" }, + '@' => { as_proto => "PMC *", as_return => "", cname => "xAT_", sig_char => 'Ps' }, +); + +for (values %signature_table) { + if (not exists $_->{as_return}) { $_->{as_return} = $_->{as_proto} } + if (not exists $_->{return_type}) { $_->{return_type} = $_->{as_proto} } + if (not exists $_->{return_type_decl}) { $_->{return_type_decl} = $_->{return_type} } + if (not exists $_->{ret_assign} and exists $_->{sig_char}) { + $_->{ret_assign} = 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "' + . $_->{sig_char} . '", return_data);'; + } + if (not exists $_->{func_call_assign}) { + $_->{func_call_assign} = "return_data = " + } +} + +=back + +=head1 FUNCTIONS + +=over + +=item C + +Converts an NCI signature to a PCC signature. + +=cut + +sub signature_nci_to_pcc { + my $nci_sig = shift; + my ($nci_ret, $nci_params) = $nci_sig =~ /^(.)\s*(\S*)/; + my $pcc_ret = $signature_table{$nci_ret}{sig_char}; + my $pcc_params = join '', map $signature_table{$_}{sig_char}, split //, $nci_params; + return "${pcc_params}->${pcc_ret}"; +} + +1; + +=back + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/src/extend.c b/src/extend.c index 0e8a3ae..aa58f2a 100644 --- a/src/extend.c +++ b/src/extend.c @@ -1747,7 +1747,6 @@ Parrot_sub_new_from_c_func(PARROT_INTERP, (char *) NULL, 0); Parrot_PMC sub = pmc_new(interp, enum_class_NCI); VTABLE_set_pointer_keyed_str(interp, sub, sig, F2DPTR(func)); - PObj_get_FLAGS(sub) |= PObj_private1_FLAG; return sub; } diff --git a/src/frame_builder.c b/src/frame_builder.c deleted file mode 100644 index e123c36..0000000 --- a/src/frame_builder.c +++ /dev/null @@ -1,618 +0,0 @@ -/* -Copyright (C) 2008-2009, Parrot Foundation. -$Id$ -*/ - -/* HEADERIZER HFILE: none */ -/* HEADERIZER STOP */ - -#include "parrot/parrot.h" -#include "pmc/pmc_fixedintegerarray.h" -#include "pmc/pmc_unmanagedstruct.h" -#include "pmc/pmc_managedstruct.h" -#include "frame_builder.h" - -/* - -=over 4 - -=item C - -This is a callback to implement the proper freeing semantics. It is called by -the ManagedStruct PMC as it is garbage collected. - -=cut - -*/ - -void -Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv) -{ - const struct jit_buffer_private_data * const jit = (struct jit_buffer_private_data*)priv; - mem_free_executable(ptr, jit->size); - free(priv); -} - -/* - -=item C - -This is a callback to implement the proper cloning semantics for jit buffers. -It is called by the ManagedStruct PMC's clone() function. - -=back - -=cut - -*/ - -PMC * -Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv) -{ - PMC * const rv = pmc_new(interp, pmc->vtable->base_type); - - VTABLE_init(interp, rv); - /* copy the attributes */ - { - void (*tmpfreefunc)(PARROT_INTERP, void*, void*); - GETATTR_ManagedStruct_custom_free_func(interp, pmc, tmpfreefunc); - SETATTR_ManagedStruct_custom_free_func(interp, rv , tmpfreefunc); - } - { - PMC* (*tmpclonefunc)(PARROT_INTERP, PMC*, void*); - GETATTR_ManagedStruct_custom_clone_func(interp, pmc, tmpclonefunc); - SETATTR_ManagedStruct_custom_clone_func(interp, rv , tmpclonefunc); - } - - { - void *freepriv, *clonepriv; - GETATTR_ManagedStruct_custom_free_priv(interp , pmc, freepriv); - GETATTR_ManagedStruct_custom_clone_priv(interp, pmc, clonepriv); - if (freepriv) { - void *tmp = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); - memcpy(tmp, freepriv, sizeof (struct jit_buffer_private_data)); - SETATTR_ManagedStruct_custom_free_priv(interp, rv , tmp); - if (clonepriv == freepriv) { - /* clonepriv is a copy of freepriv, make it a copy in the clone too. */ - SETATTR_ManagedStruct_custom_clone_priv(interp, rv , tmp); - clonepriv = NULL; /* disable the clonepriv copying below */ - } - } - if (clonepriv) { - void *tmp = mem_sys_allocate(sizeof (struct jit_buffer_private_data)); - memcpy(tmp, clonepriv, sizeof (struct jit_buffer_private_data)); - SETATTR_ManagedStruct_custom_clone_priv(interp, rv , tmp); - } - } - - /* copy the execmem buffer */ - if (PARROT_MANAGEDSTRUCT(pmc)->ptr) { - struct jit_buffer_private_data *jit = (struct jit_buffer_private_data*)priv; - void *ptr = PARROT_MANAGEDSTRUCT(pmc)->ptr; - void *newptr = mem_alloc_executable(jit->size); - if (!newptr) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Cannot allocate executable memory"); - memcpy(newptr, ptr, jit->size); - PARROT_MANAGEDSTRUCT(rv)->ptr = newptr; - } - - return rv; -} - - -int -emit_is8bit(long disp) -{ - return disp >= -128 && disp <= 127; -} - -char * -emit_disp8_32(char *pc, int disp) -{ - if (emit_is8bit(disp)) { - *(pc++) = (char)disp; - return pc; - } - else { - *(long *)pc = disp; - return pc + 4; - } -} - -void -emit_sib(PARROT_INTERP, char *pc, int scale, int i, int base) -{ - int scale_byte; - - switch (scale) { - case 1: - scale_byte = emit_Scale_1; - break; - case 2: - scale_byte = emit_Scale_2; - break; - case 4: - scale_byte = emit_Scale_4; - break; - case 8: - scale_byte = emit_Scale_8; - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Invalid scale factor %d\n", scale); - return; - } - - *pc = (char)(scale_byte | (i == emit_None ? emit_Index_None : emit_reg_Index(i)) | - emit_reg_Base(base)); -} - -char * -emit_r_X(PARROT_INTERP, char *pc, int reg_opcode, int base, int i, int scale, long disp) -{ - if (i && !scale) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "emit_r_X passed invalid scale+index combo\n"); - - if (base == emit_EBP) { - /* modrm disp */ - if (i == emit_None) { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_reg_rm(emit_EBP)); - return emit_disp8_32(pc, disp); - } - /* modrm sib disp */ - else { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_b100); - emit_sib(interp, pc++, scale, i, base); - return emit_disp8_32(pc, disp); - } - } - - /* modrm sib disp */ - if (base == emit_ESP) { - *(pc++) = (char)((emit_is8bit(disp) ? emit_Mod_b01 : emit_Mod_b10) - | reg_opcode | emit_rm_b100); - emit_sib(interp, pc++, scale, i, emit_ESP); - return emit_disp8_32(pc, disp); - } - - /* modrm disp32 */ - if (!base && !(i && scale)) { - *(pc++) = (char)(emit_Mod_b00 | reg_opcode | emit_rm_b101); - *(long *)pc = disp; - return pc + 4; - } - - /* Ok, everything should be more regular here */ - *(pc++) = (char)((disp == 0 ? emit_Mod_b00 : - (emit_is8bit(disp) ? - emit_Mod_b01 : emit_Mod_b10)) | - reg_opcode | - (!base || (scale && i) ? emit_rm_b100 : emit_reg_rm(base))); - - if (!base || (scale && i)) { - emit_sib(interp, pc++, scale, i, base); - } - if (disp) - pc = emit_disp8_32(pc, disp); - - return pc; -} - -char * -emit_shift_i_r(PARROT_INTERP, char *pc, int opcode, int imm, int reg) -{ - if (opcode == emit_b000 && imm < 0) { - opcode = emit_b001; /* -rol => 32 + ror */ - imm = -imm; - } - - if (imm == 0) { - /* noop */ - } - else if (imm == 1) { - *(pc++) = (char) 0xd1; - *(pc++) = (char) emit_alu_X_r(opcode, reg); - } - else if (imm > 1 && imm < 33) { - *(pc++) = (char) 0xc1; - *(pc++) = (char) emit_alu_X_r(opcode, reg); - *(pc++) = (char)imm; - } - else { - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "emit_shift_i_r passed invalid shift\n"); - } - - return pc; -} - -char * -emit_popl_r(char *pc, int reg) -{ - *(pc++) = (char)(0x58 | (reg - 1)); - return pc; -} - -unsigned char *lastpc; - -size_t -calc_signature_needs(const char *sig, int *strings) -{ - size_t stack_size = 0; - while (*sig) { - switch (*sig) { - case 't': - (*strings)++; - stack_size +=4; - break; - case 'd': - stack_size +=8; - break; - default: - stack_size +=4; - break; - } - sig++; - } - return stack_size; - -} - -/* - * The function generated here is called as func(interp, nci_info) - * interp ... 8(%ebp) - * nci_info ... 12(%ebp) - * - * The generate function for a specific signature looks quite similar to - * an optimized compile of src/nci.c:pcf_x_yy(). In case of any troubles - * just compare the disassembly. - * - * If a non-NULL sizeptr is passed, the integer it points to will be written - * with the size of the allocated execmem buffer. - */ - -void * -Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, STRING *signature, int *sizeptr) -{ - char *pc; - char *execmem; - int i = 0; - int arg_count = 0; - int string_buffer_count = 0; - const int ST_SIZE_OF = 124; - const int JIT_ALLOC_SIZE = 1024; - - char *signature_str = Parrot_str_to_cstring(interp, signature); - /* skip over the result */ - char *sig = signature_str + 1; - size_t stack_space_needed = calc_signature_needs(sig, - &string_buffer_count); - - int base_offset = 0; - int strings_offset = base_offset - (sizeof (char *) * string_buffer_count); - int st_offset = strings_offset - ST_SIZE_OF; - int args_offset = st_offset - stack_space_needed; - int temp_calls_offset = args_offset - 16; - int total_stack_needed = -temp_calls_offset; - - /* - * ESP - * 0-15, 16 bytes for utility calls - * stack_space_needed for actual NCI call - * st - * STRINGS -> char * holding space - * EBP - */ - - /* this ought to be enough - the caller of this function - * should free the function pointer returned here - */ - pc = execmem = (char *)mem_alloc_executable(JIT_ALLOC_SIZE); - if (! pc) - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Cannot allocate executable memory"); - - - /* this generated jit function will be called as (INTERP (EBP 8), func_ptr - * (ESP 12), args signature (ESP 16)) */ - - /* make stack frame, preserve %ebx */ - jit_emit_stack_frame_enter(pc); - - emitm_subl_i_r(pc, total_stack_needed, emit_ESP); - - /* Parrot_init_arg_nci(interp, &st, "S"); */ - /* args signature "S" */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 16); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /*&st*/ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /*interpreter*/ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - /* XXX FIXME This whole function require major rework */ - /* XXX FIXME if (sig && *sig) */ - /* XXX FIXME emitm_call_cfunc(pc, Parrot_init_arg_nci); */ - - while (*sig) { - emitm_movl_i_m(pc, arg_count, emit_EBP, 0, 1, temp_calls_offset + 8); - - switch (*sig) { - case '0': /* null ptr or such - doesn't consume a reg */ - jit_emit_bxor_rr_i(interp, pc, emit_EAX, emit_EAX); - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'f': - /* FIXME emitm_call_cfunc(pc, get_nci_N); */ - emitm_fstps(interp, pc, emit_EBP, 0, 1, args_offset); - break; - case 'N': - case 'd': - /* FIXME emitm_call_cfunc(pc, get_nci_N); */ - emitm_fstpl(interp, pc, emit_EBP, 0, 1, args_offset); - args_offset += 4; - break; - case 'I': /* INTVAL */ - case 'l': /* long */ - case 'i': /* int */ - /* FIXME emitm_call_cfunc(pc, get_nci_I); */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 't': /* string, pass a cstring */ - /* FIXME emitm_call_cfunc(pc, get_nci_S); */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - emitm_call_cfunc(pc, string_to_cstring_nullable); - - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - /* save off temporary allocation address */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, strings_offset); - strings_offset += 4; - - /* reset ESP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - break; - case 's': /* short: movswl intreg_o(base), %eax */ - /* FIXME emitm_call_cfunc(pc, get_nci_I); */ - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'c': /* char: movsbl intreg_o(base), %eax */ - /* emitm_call_cfunc(pc, get_nci_I); */ - emitm_movsbl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'J': /* interpreter */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - arg_count--; - break; - case 'p': /* push pmc->data */ - /* FIXME emitm_call_cfunc(pc, get_nci_p); */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'O': /* push PMC * object in P2 */ - case 'P': /* push PMC * */ - case '@': - /* FIXME emitm_call_cfunc(pc, get_nci_P); */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'v': - break; - case 'b': /* buffer (void*) pass Buffer_bufstart(SReg) */ - /* FIXME emitm_call_cfunc(pc, get_nci_S); */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, - (size_t) &Buffer_bufstart((STRING *) NULL)); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */ - /* FIXME emitm_call_cfunc(pc, get_nci_S); */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, - (size_t) &Buffer_bufstart((STRING *) NULL)); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - case 'S': - /* FIXME emitm_call_cfunc(pc, get_nci_S); */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, args_offset); - break; - - - /* I have no idea how to handle these */ - case '2': - case '3': - case '4': - case 'V': - mem_free_executable(execmem, JIT_ALLOC_SIZE); - Parrot_str_free_cstring(signature_str); - return NULL; - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown arg Signature %c\n", *sig); - /* - * oops unknown signature: - * cleanup and try nci.c - */ - mem_free_executable(execmem, JIT_ALLOC_SIZE); - Parrot_str_free_cstring(signature_str); - return NULL; - } - args_offset +=4; - arg_count++; - sig++; - } - - /* prepare to call VTABLE_get_pointer, set up args */ - /* interpreter - movl 8(%ebp), %eax */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - /* pmc - movl 12(%ebp), %eax */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 12); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /* get the get_pointer() pointer from the pmc's vtable */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(PMC, vtable)); - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(VTABLE, get_pointer)); - - /* call get_pointer(), result goes into eax */ - emitm_callr(pc, emit_EAX); - emitm_addl_i_r(pc, 16, emit_ESP); - - /* call the resulting function pointer */ - emitm_callr(pc, emit_EAX); - emitm_subl_i_r(pc, 16, emit_ESP); - - /* SAVE OFF EAX */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /*&st*/ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /*interpreter*/ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, 8); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 0); - - /* RESTORE BACK EAX */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* now place return value in registers */ - /* first in signature is the return value */ - sig = signature_str; /* the result */ - switch (*sig) { - /* I have no idea how to handle these */ - case '2': - case '3': - case '4': - /* get integer from pointer - untested */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, 0); - if (*sig == 2) /* short */ - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_I);*/ - break; - case 'f': - case 'd': - jit_emit_fstore_mb_n(interp, pc, emit_EBP, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_N); */ - /* pop num from st(0) and mov to reg */ - break; - case 's': - /* movswl %ax, %eax */ - emitm_movswl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */ - break; - case 'c': - /* movsbl %al, %eax */ - emitm_movsbl_r_r(pc, emit_EAX, emit_EAX); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */ - break; - case 'I': /* INTVAL */ - case 'l': - case 'i': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_I); */ - break; - case 'v': /* void - do nothing */ - break; - case 'P': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_P); */ - break; - case 'p': /* make a new unmanaged struct */ - /* save return value on stack */ - - /* save pointer p */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 12); - - /* make new pmc */ - emitm_movl_i_m(pc, enum_class_UnManagedStruct, emit_EBP, 0, 1, temp_calls_offset + 4); - emitm_call_cfunc(pc, pmc_new); - - /* restore pointer p to EDX */ - emitm_movl_m_r(interp, pc, emit_EDX, emit_EBP, 0, 1, temp_calls_offset + 12); - - /* copy UnManagedStruct to stack for set_nci_P call */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* eax = PMC, get return value into edx */ - /* mov data(%eax), %eax - mov %edx, ptr(%eax) */ - emitm_movl_m_r(interp, pc, emit_EAX, emit_EAX, 0, 1, offsetof(struct PMC, data)); - emitm_movl_r_m(interp, pc, emit_EDX, emit_EAX, 0, 1, - offsetof(struct Parrot_UnManagedStruct_attributes, ptr)); - - /* reset EBP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /* XXX FIXME emitm_call_cfunc(pc, set_nci_P); */ - break; - case 'S': - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - /* XXX FIXME emitm_call_cfunc(pc, set_nci_S); */ - break; - case 't': /* string */ - /* EAX is char* */ - emitm_movl_i_m(pc, 0, emit_EBP, 0, 1, temp_calls_offset + 8); /* len */ - - /* overwrites address of st in EBP(4) */ - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - emitm_call_cfunc(pc, Parrot_str_new); - - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 8); - - /* reset EBP(4) */ - emitm_lea_m_r(interp, pc, emit_EAX, emit_EBP, 0, 1, st_offset); - emitm_movl_r_m(interp, pc, emit_EAX, emit_EBP, 0, 1, temp_calls_offset + 4); - - /* XXX FIXME emitm_call_cfunc(pc, set_nci_S); */ - break; - default: - Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown return Signature %c\n", *sig); - /* - * oops unknown signature: - * cleanup and try nci.c - */ - Parrot_str_free_cstring(signature_str); - mem_free_executable(execmem, JIT_ALLOC_SIZE); - return NULL; - } - - /* free temporary strings */ - strings_offset = st_offset + ST_SIZE_OF; - for (i=0; i #include "parrot/parrot.h" -#include "parrot/hash.h" -#include "parrot/oplib/ops.h" /* * NCI interface */ + void * -Parrot_jit_build_call_func(Interp *, PMC *, STRING *, int *); +Parrot_jit_build_call_func(Interp *, PMC *, STRING *, void **); /* custom pmc callback functions */ void @@ -37,1328 +32,11 @@ Parrot_jit_free_buffer(PARROT_INTERP, void *ptr, void *priv); PMC* Parrot_jit_clone_buffer(PARROT_INTERP, PMC *pmc, void *priv); -struct jit_buffer_private_data { - int size; -}; - -/* Scale factor values */ -#define emit_Scale(scale) ((scale) << 6) -#define emit_Scale_1 emit_Scale(0) -#define emit_Scale_2 emit_Scale(1) -#define emit_Scale_4 emit_Scale(2) -#define emit_Scale_8 emit_Scale(3) - -/* ESIB byte */ -#define emit_reg_Index(x) (((x)-1) << 3) -#define emit_reg_Base(x) ((x)-1) -#define emit_Index_None ((emit_b100) << 3) - /* * helper funcs - get argument n */ -/* - * if we have a delegated method like typeof_i_p, that returns an INTVAL - * and that is all in a sequence of JITted opcodes, and when these INTVAL - * is MAPped, we got a problem. So the EXT_CALL flag is disabled - mapped - * registers are saved/restored around vtable calls. - */ -#define JIT_VTABLE_OPS 1 - -/* EXEC_SHARED generates code to be used with libparrot.so - * It grabs the real address of cgp_core from the gcc generated code - * x/1i cgp_code - * jmp *0xXXXX - * x/1wx 0xXXXX - * real address of cpg_core - * s. exec_emit_end - * XXX This should be a command line option. - */ -#undef EXEC_SHARED - -extern UINTVAL ld(UINTVAL); - -#define NEG_MINUS_ZERO -/* #define NEG_ZERO_SUB */ - -/* Register codes */ -#define emit_None 0 - -/* These are + 1 the real values */ -#define emit_EAX 1 -#define emit_ECX 2 -#define emit_EDX 3 -#define emit_EBX 4 -#define emit_ESP 5 -#define emit_EBP 6 -#define emit_ESI 7 -#define emit_EDI 8 - -/* Scratch register. */ - -#define ISR1 emit_EAX -#define FSR1 0 - -#define emit_b00 0 -#define emit_b01 1 -#define emit_b10 2 -#define emit_b11 3 - -#define emit_b000 0 -#define emit_b001 1 -#define emit_b010 2 -#define emit_b011 3 -#define emit_b100 4 -#define emit_b101 5 -#define emit_b110 6 -#define emit_b111 7 - -/* Mod R/M byte */ -#define emit_reg(x) ((x) << 3) -#define emit_Mod(Mod) ((Mod) << 6) -#define emit_reg_rm(x) ((x)-1) - -/* Mod values for Mod R/M Byte */ -#define emit_Mod_b00 emit_Mod(emit_b00) -#define emit_Mod_b01 emit_Mod(emit_b01) -#define emit_Mod_b10 emit_Mod(emit_b10) - -/* special R/M values */ -#define emit_rm_b101 emit_b101 -#define emit_rm_b100 emit_b100 - -#define emit_r_m(interp, pc, reg1, b, i, s, d) \ - emit_r_X((interp), (pc), emit_reg((reg1)-1), (b), (i), (s), (d)) - -#define emit_alu_X_r(X, reg) ((emit_b11 << 6) | ((X) << 3) | ((reg) - 1)) - -#define emit_alu_r_r(reg1, reg2) emit_alu_X_r(((reg1) - 1), (reg2)) - -int emit_is8bit(long disp); - -char * emit_disp8_32(char *pc, int disp); - -void emit_sib(PARROT_INTERP, char *pc, int scale, int i, int base); - -char * emit_r_X(PARROT_INTERP, char *pc, int reg_opcode, int base, int i, - int scale, long disp); - -char * emit_shift_i_r(PARROT_INTERP, char *pc, int opcode, int imm, int reg); - -char * emit_shift_i_m(PARROT_INTERP, char *pc, int opcode, int imm, - int base, int i, int scale, long disp); - -char * emit_shift_r_r(PARROT_INTERP, char *pc, int opcode, int reg1, int reg2); - -char * emit_shift_r_m(PARROT_INTERP, char *pc, int opcode, int reg, - int base, int i, int scale, long disp); - -/* CDQ - need this to do multiply */ -#define emitm_cdq(pc) *((pc)++) = (char) 0x99 - -/* RET */ -#define emitm_ret(pc) *((pc)++) = (char) 0xc3 - -/* NOP */ -#define emit_nop(pc) *((pc)++) = (char) 0x90 - -/* PUSHes */ - -#define emitm_pushl_r(pc, reg) \ - *((pc)++) = (char) 0x50 | ((reg) - 1) - -#define emitm_pushl_i(pc, imm) { \ - *((pc)++) = (char) 0x68; \ - *(long *)(pc) = (long)(imm); \ - (pc) += 4; } - -#define emitm_pushl_m(pc, mem) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char) 0x35; \ - *(long *)(pc) = (long)(mem); \ - (pc) += 4; } - -char * emit_pushl_m(PARROT_INTERP, char *pc, int base, int i, int scale, - long disp); - -/* POPs */ - -char * emit_popl_r(char *pc, int reg); - -# define emitm_popl_r(pc, reg) \ - (pc) = emit_popl_r((pc), (reg)) - -char * emit_popl_m(PARROT_INTERP, char *pc, int base, int i, int scale, - long disp); - -/* MOVes */ - -char * emit_movb_r_r(char *pc, int reg1, int reg2); - -# define jit_emit_mov_rr_i(pc, reg2, reg1) if ((reg1) != (reg2)) { \ - *((pc)++) = (char) 0x89; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); } - -# define jit_emit_mov_ri_i(interp, pc, reg, imm) { \ - *((pc)++) = (char)(0xb8 | ((reg) - 1)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -# define emitm_movX_Y_Z(interp, op, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) (op); \ - (pc) = emit_r_m((interp), (pc), (reg1), (b), (i), (s), (long)(d)); } - -# define emitm_movb_r_m(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x88, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_movl_r_m(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x89, (pc), (reg1), (b), (i), (s), (d)) - -/* move byte/word with sign extension */ -# define emitm_movsbl_r_m(interp, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) 0x0f; \ - emitm_movX_Y_Z((interp), 0xBE, (pc), (reg1), (b), (i), (s), (d)); \ -} - -# define emitm_movswl_r_m(interp, pc, reg1, b, i, s, d) { \ - *((pc)++) = (char) 0x0f; \ - emitm_movX_Y_Z((interp), 0xBF, (pc), (reg1), (b), (i), (s), (d)); \ -} - -# define emitm_movsbl_r_r(pc, reg1, reg2) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char) 0xbe; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); \ -} - -# define emitm_movswl_r_r(pc, reg1, reg2) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char) 0xbf; \ - *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); \ -} - -# define emitm_movb_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8a, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_movl_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8b, (pc), (reg1), (b), (i), (s), (d)) - -# define emitm_lea_m_r(interp, pc, reg1, b, i, s, d) \ - emitm_movX_Y_Z((interp), 0x8d, (pc), (reg1), (b), (i), (s), (d)) - -char * emit_movb_i_m(PARROT_INTERP, char *pc, char imm, int base, int i, - int scale, long disp); - -# define emitm_movl_i_m(pc, imm, b, i, s, d) { \ - *((pc)++) = (char) 0xc7; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b000), (b), (i), (s), (long)(d)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -/* Various ALU formats */ - -# define emitm_alul_r_r(pc, op, reg1, reg2) { \ - *((pc)++) = (char) (op); *((pc)++) = (char) emit_alu_r_r((reg1), (reg2)); } - -# define emitm_alub_i_r(pc, op1, op2, imm, reg) { \ - *((pc)++) = (char) (op1); *((pc)++) = (char) emit_alu_X_r((op2), (reg)); *((pc)++) = (char)(imm); } - -# define emitm_alul_i_r(pc, op1, op2, imm, reg) { \ - *((pc)++) = (char) (op1); \ - *((pc)++) = (char) emit_alu_X_r((op2), (reg)); \ - *(long *)((pc)) = (long)(imm); (pc) += 4; } - -# define emitm_alul_i_m(pc, op1, op2, imm, b, i, s, d) { \ - *((pc)++) = (char) (op1); \ - (pc) = emit_r_X((interp), (pc), emit_reg(op2), (b), (i), (s), (d)); \ - *(long *)(pc) = (long)(imm); (pc) += 4; } - -# define emitm_alul_r_m(pc, op, reg, b, i, s, d) { \ - *((pc)++) = (char) (op); \ - (pc) = emit_r_X((interp), (pc), emit_reg((reg)-1), (b), (i), (s), (long)(d)); } - -/* ADDs */ - -# define emitm_addb_r_r(pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x00, (reg1), (reg2)) - -# define emitm_addb_i_r(pc, imm, reg) \ - emitm_alub_i_r((pc), 0x83, emit_b000, (imm), (reg)) - -# define jit_emit_add_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x01, (reg2), (reg1)) - -# define jit_emit_add_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg)) - -# define emitm_addl_i_r(pc, imm, reg) \ - emitm_alul_i_r((pc), 0x81, emit_b000, (imm), (reg)) - -# define emitm_addl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b000, (imm), (b), (i), (s), (d)) - -# define emitm_addl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x01, (reg), (b), (i), (s), (d)) - -# define emitm_addl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x03, (reg), (b), (i), (s), (d)) - -/* SUBs */ - -# define jit_emit_sub_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x29, (reg2), (reg1)) - -# define emitm_subl_i_r(pc, imm, reg) \ - emitm_alul_i_r((pc), 0x81, emit_b101, (imm), (reg)) - -# define jit_emit_sub_ri_i(interp, pc, r, i) emitm_subl_i_r((pc), (i), (r)) - -# define emitm_subl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x29, (reg), (b), (i), (s), (d)) - -# define emitm_subl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x2b, (reg), (b), (i), (s), (d)) - -# define emitm_subl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b101, (imm), (b), (i), (s), (d)) - -/* These are used by both signed and unsigned EDIV, but only unsigned MUL */ -# define emitm_alu_imp_r(pc, op, reg) { \ - *((pc)++) = (char) 0xf7; \ - *((pc)++) = (char) emit_alu_X_r((op), (reg)); } - -# define emitm_alu_imp_m(pc, op, b, i, s, d) { \ - *((pc)++) = (char) 0xf7; \ - (pc) = emit_r_X((interp), (pc), emit_reg(op), (b), (i), (s), (d)); } - -/* Unsigned MUL and EDIV */ -/* EAX implicit destination in multiply and divide */ - -# define emitm_umull_r(pc, reg2) emitm_alu_imp_r((pc), emit_b100, (reg2)) - -# define emitm_udivl_r(pc, reg2) emitm_alu_imp_r((pc), emit_b110, (reg2)) - -# define emitm_umull_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b100, (b), (i), (s), (d)) - -# define emitm_udivl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b110, (b), (i), (s), (d)) - -/* Signed MUL and EDIV */ - -# define emitm_sdivl_r(pc, reg2) emitm_alu_imp_r((pc), emit_b111, (reg2)) - -# define emitm_sdivl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b111, (b), (i), (s), (d)) - -# define jit_emit_cdq(pc) *(pc)++ = 0x99 - -/* TEST for zero */ -# define jit_emit_test_r_i(pc, reg1) emitm_alul_r_r((pc), 0x85, (reg1), (reg1)) - -# define emitm_smull_r(pc, reg2) emitm_alu_imp_r((pc), emit_b101, (reg2)) - -# define jit_emit_mul_rr_i(interp, pc, reg1, reg2) { \ - *(pc)++ = 0xf; \ - emitm_alul_r_r((pc), 0xaf, (reg1), (reg2)); } - -# define emitm_smull_r_m(pc, reg1, b, i, s, d) { \ - *(pc)++ = 0xf; \ - emitm_alul_r_m((pc), 0xaf, (reg1), (b), (i), (s), (d)); } - -char * opt_mul(PARROT_INTERP, char *pc, int dest, INTVAL imm, int src); - -# define jit_emit_mul_rir_i(pc, dest, imm, src) \ - (pc) = opt_mul(interp, (pc), (dest), (imm), (src)) - - -# define jit_emit_mul_ri_i(pc, r, imm) jit_emit_mul_rir_i((pc), (r), (imm), (r)) - -# define jit_emit_mul_RIM_ii(pc, reg, imm, ofs) \ - emitm_alul_r_m((pc), 0x69, (reg), emit_EBX, emit_None, 1, (ofs)); \ - *(long *)(pc) = (long)(imm); \ - (pc) += 4; - -/* NEG */ - -# define jit_emit_neg_r_i(pc, reg) emitm_alu_imp_r((pc), emit_b011, (reg)) - -# define emitm_negl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b011, (b), (i), (s), (d)) - -/* AND */ - -# define emit_andl_r_r(pc, reg1, reg2) emitm_alul_r_r((pc), 0x21, (reg1), (reg2)) -# define jit_emit_band_rr_i(interp, pc, r1, r2) emit_andl_r_r((pc), (r2), (r1)) - -# define jit_emit_band_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b100, (imm), (reg)) - -# define emitm_andl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x21, (reg), (b), (i), (s), (d)) - -# define emitm_andl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x23, (reg), (b), (i), (s), (d)) - -# define emitm_andl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b100, (imm), (b), (i), (s), (d)) - -/* TEST op */ -# define jit_emit_test_rr_i(pc, r1, r2) emitm_alul_r_r((pc), 0x85, (r1), (r2)) - -# define jit_emit_test_ri_i(pc, r, im) \ - emitm_alul_i_r((pc), 0xF7, emit_b000, (im), (r)) - -# define jit_emit_test_RM_i(pc, r, offs) \ - emitm_alul_r_m((pc), 0x85, (r), emit_EBX, 0, 1, (offs)) - -/* OR */ - -# define jit_emit_bor_rr_i(interp, pc, reg1, reg2) emitm_alul_r_r((pc), 0x9, (reg2), (reg1)) - -# define jit_emit_bor_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b001, (imm), (reg)) - -# define emitm_orl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x09, (reg), (b), (i), (s), (d)) - -# define emitm_orl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x0b, (reg), (b), (i), (s), (d)) - -# define emitm_orl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b001, (imm), (b), (i), (s), (d)) - -/* XOR */ - -# define jit_emit_bxor_rr_i(interp, pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x31, (reg2), (reg1)) - -# define jit_emit_bxor_ri_i(intepr, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b110, (imm), (reg)) - -# define emitm_xorl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x31, (reg), (b), (i), (s), (d)) - -# define emitm_xorl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x33, (reg), (b), (i), (s), (d)) - -# define emitm_xorl_i_m(pc, imm, b, i, s, d) \ - emitm_alul_i_m((pc), 0x81, emit_b110, (imm), (b), (i), (s), (d)) - -/* NOT */ - -# define jit_emit_not_r_i(pc, reg) emitm_alu_imp_r((pc), emit_b010, (reg)) -# define emitm_notl_m(pc, b, i, s, d) \ - emitm_alu_imp_m((pc), emit_b010, (b), (i), (s), (d)) - -# define jit_emit_not_M_i(interp, pc, offs) emitm_notl_m((pc), emit_EBX, 0, 1, (offs)) - -/* XCHG */ -# define jit_emit_xchg_rr_i(interp, pc, r1, r2) { \ - if ((r1) != (r2)) { \ - *((pc)++) = (char) 0x87; \ - *((pc)++) = (char) emit_alu_r_r((r1), (r2)); \ - } \ -} - -# define jit_emit_xchg_rm_i(pc, r, m) { \ - emitm_alul_r_m((pc), 0x87, (r), emit_None, emit_None, emit_None, (m)) \ -} -# define jit_emit_xchg_RM_i(interp, pc, r, offs) { \ - emitm_alul_r_m((pc), 0x87, (r), emit_EBX, emit_None, 1, (offs)) \ -} -# define jit_emit_xchg_MR_i(interp, pc, offs, r) jit_emit_xchg_RM_i((interp), (pc), (r), (offs)) - -/* SHL */ - -# define jit_emit_shl_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b100, (imm), (reg)); } - -# define emitm_shll_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b100, (imm), (b), (i), (s), (d)); } - -# define emitm_shll_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b100, (reg1), (reg2)); } - -# define emitm_shll_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b100, (reg), (b), (i), (s), (d)); } - -/* SHR */ - -# define jit_emit_lsr_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b101, (imm), (reg)); } - -# define emitm_shrl_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b101, (imm), (b), (i), (s), (d)); } - -# define emitm_shrl_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b101, (reg1), (reg2)); } - -# define emitm_shrl_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b101, (reg), (b), (i), (s), (d)); } - -/* SAL */ - -# define emitm_sall_i_r(interp, pc, imm, reg) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b100, (imm), (reg)); } - -# define emitm_sall_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b100, (imm), (b), (i), (s), (d)); } - -# define emitm_sall_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b100, (reg1), (reg2)); } - -# define emitm_sall_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b100, (reg), (b), (i), (s), (d)); } - -/* SAR */ - -# define jit_emit_shr_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b111, (imm), (reg)); } - - -# define emitm_sarl_i_m(pc, imm, b, i, s, d) \ - { (pc) = emit_shift_i_m((pc), emit_b111, (imm), (b), (i), (s), (d)); } - -# define emitm_sarl_r_r(interp, pc, reg1, reg2) \ - { (pc) = emit_shift_r_r((interp), (pc), emit_b111, (reg1), (reg2)); } - -# define emitm_sarl_r_m(pc, reg, b, i, s, d) \ - { (pc) = emit_shift_r_m((pc), emit_b111, (reg), (b), (i), (s), (d)); } - -/* rotate */ - -# define jit_emit_rol_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b000, (imm), (reg)); } - -# define jit_emit_ror_ri_i(interp, pc, reg, imm) \ - { (pc) = emit_shift_i_r((interp), (pc), emit_b001, (imm), (reg)); } - -/* interface, shift r1 by r2 bits */ - -# define jit_emit_shl_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b100) - -# define jit_emit_shl_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b100) - -/* shr seems to be the arithmetic shift */ -# define jit_emit_shr_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b111) - -# define jit_emit_shr_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b111) - -# define jit_emit_lsr_rr_i(interp, pc, r1, r2) \ - (pc) = opt_shift_rr((interp), jit_info, (r1), (r2), emit_b101) - -# define jit_emit_lsr_RM_i(interp, pc, r1, offs) \ - (pc) = opt_shift_rm((interp), jit_info, (r1), (offs), emit_b101) - -/* MOV (reg), reg */ -# define emit_movm_r_r(pc, src, dest) \ - *((pc)++) = (char) 0x8b; \ - *((pc)++) = (char) (src) | (dest) << 3 - -/* MOV X(reg), reg */ -# define emit_movb_i_r_r(pc, imm, src, dest) \ - *((pc)++) = (char)(0x8b); \ - *((p)c++) = (char)(0x40 | ((src) - 1) | ((dest) - 1) << 3); \ - *((pc)++) = (imm) - -/* INC / DEC */ -# define jit_emit_inc_r_i(pc, reg) *((pc)++) = (char)(0x40 | ((reg) - 1)) -# define jit_emit_dec_r_i(pc, reg) *((pc)++) = (char)(0x48 | ((reg) - 1)) - -/* Floating point ops */ - -# define emitm_floatop 0xd8 /* 11011000 */ -# define jit_emit_dec_fsp(pc) { *((pc)++) = (char) 0xD9; *((pc)++) = (char) 0xF6; } -# define jit_emit_inc_fsp(pc) { *((pc)++) = (char) 0xD9; *((pc)++) = (char) 0xF7; } - -# define emitm_fl_2(interp, pc, mf, opa, opb, b, i, s, d) { \ - *((pc)++) = (char)(emitm_floatop | ((mf) << 1) | (opa)); \ - (pc) = emit_r_X((interp), (pc), emit_reg(opb), (b), (i), (s), (long)(d)); } - -# define emitm_fl_3(pc, d_p_opa, opb_r, sti) { \ - *((pc)++) = (char)(emitm_floatop | (d_p_opa)); \ - *((pc)++) = (char)(0xc0 | ((opb_r) << 3) | (sti)); } - -# define emitm_fl_4(pc, op) { \ - *((pc)++) = (char)(emitm_floatop | emit_b001); \ - *((pc)++) = (char)(0xe0 | (op)); } - -/* Integer loads and stores */ -# define emitm_fildl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fistpl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b011, (b), (i), (s), (d)) - -# define emitm_fistl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b010, (b), (i), (s), (d)) - -/* long long integer load/store */ -# define emitm_fildll(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b11, 1, emit_b101, (b), (i), (s), (d)) - -# define emitm_fistpll(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b11, 1, emit_b111, (b), (i), (s), (d)) - -/* Double loads and stores */ -# define emitm_fldl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fstpl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b011, (b), (i), (s), (d)) - -# define emitm_fstl(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 1, emit_b010, (b), (i), (s), (d)) - -/* long double load / store */ -# define emitm_fldt(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b101, (b), (i), (s), (d)) - -# define emitm_fstpt(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 1, emit_b111, (b), (i), (s), (d)) - -/* short float load / store */ -# define emitm_flds(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b000, (b), (i), (s), (d)) - -# define emitm_fstps(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b010, (b), (i), (s), (d)) - -#if NUMVAL_SIZE == 8 - -# define jit_emit_fload_m_n(interp, pc, address) \ - emitm_fldl((interp), (pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fload_mb_n(interp, pc, base, offs) \ - emitm_fldl((interp), (pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fstore_m_n(interp, pc, address) \ - emitm_fstpl((interp), (pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fstore_mb_n(interp, pc, base, offs) \ - emitm_fstpl((interp), (pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fst_mb_n(interp, pc, base, offs) \ - emitm_fstl((interp), (pc), (base), emit_None, 1, (offs)) - -#else /* NUMVAL_SIZE */ - -# define jit_emit_fload_m_n(interp, pc, address) \ - emitm_fldt((pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fload_mb_n(interp, pc, base, offs) \ - emitm_fldt((pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fstore_m_n(pc, address) \ - emitm_fstpt((pc), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_fstore_mb_n(interp, pc, base, offs) \ - emitm_fstpt((pc), (base), emit_None, 1, (offs)) - -# define jit_emit_fst_mb_n(interp, pc, base, offs) \ - emitm_fstt((pc), (base), emit_None, 1, (offs)) - -#endif /* NUMVAL_SIZE */ - -#if INTVAL_SIZE == 4 - -# define jit_emit_fload_m_i(interp, pc, address) \ - emitm_fildl((interp), (pc), emit_None, emit_None, emit_None, (address)) -# define jit_emit_fload_mb_i(interp, pc, offs) \ - emitm_fildl((interp), (pc), emit_EBX, emit_None, 1, (offs)) -# define jit_emit_fstore_m_i(pc, m) \ - emitm_fistpl((pc), emit_None, emit_None, emit_None, (m)) - -#else /* INTVAL_SIZE */ - -# define jit_emit_fload_m_i(interp, pc, address) \ - emitm_fildll((interp), (pc), emit_None, emit_None, emit_None, (address)) -# define jit_emit_fload_mb_i(interp, pc, offs) \ - emitm_fildll((interp), (pc), emit_EBX, emit_None, 1, (offs)) -# define jit_emit_fstore_m_i(pc, m) \ - emitm_fistpll((pc), emit_None, emit_None, emit_None, (m)) - -#endif /* INTVAL_SIZE */ - -/* 0xD8 ops */ -# define emitm_fadd(pc, sti) emitm_fl_3((pc), emit_b000, emit_b000, (sti)) -# define emitm_fmul(pc, sti) emitm_fl_3((pc), emit_b000, emit_b001, (sti)) -# define emitm_fsub(pc, sti) emitm_fl_3((pc), emit_b000, emit_b100, (sti)) -# define emitm_fdiv(pc, sti) emitm_fl_3((pc), emit_b000, emit_b110, (sti)) - -/* 0xD9 ops */ -# define emitm_fldz(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xee; } -# define emitm_fld1(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xe8; } -# define emitm_fsqrt(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xfa; } -# define emitm_fsin(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xfe; } -# define emitm_fcos(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xff; } -# define emitm_fxam(pc) { *((pc)++) = (char) 0xd9; *((pc)++) = (char) 0xe5; } - -/* FXCH ST, ST(i) , optimize 2 consecutive fxch with same reg */ -# define emitm_fxch(pc, sti) { \ - emitm_fl_3((pc), emit_b001, emit_b001, (sti)); \ -} - -/* FLD ST, ST(i), optimized FSTP(N+1);FLD(N) => FST(N+1) */ -extern unsigned char *lastpc; -# define emitm_fld(pc, sti) do { \ - if ((unsigned char *)(pc) == (lastpc + 2) && \ - (int)(*lastpc) == (int)0xDD && \ - (int)lastpc[1] == (int)(0xD8+(sti)+1)) \ - lastpc[1] = 0xD0+(sti)+1; \ - else \ - emitm_fl_3((pc), emit_b001, emit_b000, (sti)); \ - } while (0) - -/* 0xDA, 0xDB ops */ -/* FCMOV*, FCOMI PPRO */ - -/* 0xDC like 0xD8 with reversed operands */ -# define emitm_faddr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b000, (sti)) -# define emitm_fmulr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b001, (sti)) -# define emitm_fsubr(pc, sti) emitm_fl_3((pc), emit_b100, emit_b100, (sti)) - -/* 0xDD ops */ -/* FFree ST(i) */ -# define emitm_ffree(pc, sti) emitm_fl_3((pc), emit_b101, emit_b000, (sti)) - -/* FST ST(i) = ST */ -# define emitm_fst(pc, sti) emitm_fl_3((pc), emit_b101, emit_b010, (sti)) - -/* FSTP ST(i) = ST, POP */ -# define emitm_fstp(pc, sti) { \ - lastpc = (unsigned char*) (pc); \ - emitm_fl_3((pc), emit_b101, emit_b011, (sti)); \ -} - -/* FUCOM ST(i) <=> ST unordered compares */ -# define emitm_fucom(pc, sti) emitm_fl_3((pc), emit_b101, emit_b100, (sti)) - -/* FUCOMP ST(i) <=> ST, POP */ -# define emitm_fucomp(pc, sti) emitm_fl_3((pc), emit_b101, emit_b101, (sti)) - -/* 0xDE ops */ -/* FADDP Add ST(i) = ST + ST(i); POP */ -# define emitm_faddp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b000, (sti)) - -/* FMULP Mul ST(i) = ST * ST(i); POP */ -# define emitm_fmulp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b001, (sti)) - -/* FSUB ST = ST - ST(i) */ - -/* FSUBRP SubR ST(i) = ST - ST(i); POP */ -# define emitm_fsubrp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b100, (sti)) - -/* FSUBP Sub ST(i) = ST(i) - ST; POP */ -# define emitm_fsubp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b101, (sti)) - -/* FDIVRP DivR ST(i) = ST(i) / ST(0); POP */ -# define emitm_fdivrp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b110, (sti)) - -/* FDIVP Div ST(i) = ST(0) / ST(i); POP ST(0) */ -# define emitm_fdivp(pc, sti) emitm_fl_3((pc), emit_b110, emit_b111, (sti)) - -/* 0xDF OPS: FCOMIP, FUCOMIP PPRO */ - -/* Negate - called change sign */ -# define emitm_fchs(pc) emitm_fl_4((pc), 0) - -/* ABS - ST(0) = ABS(ST(0)) */ -# define emitm_fabs(pc) emitm_fl_4((pc), 1) - -/* Comparisons */ - -# define emitm_fcom(pc, sti) emitm_fl_3((pc), emit_b000, emit_b010, (sti)) - -# define emitm_fcomp(pc, sti) emitm_fl_3((pc), emit_b000, emit_b011, (sti)) - -#ifdef PARROT_HAS_JIT_FCOMIP -# define emitm_fcomip(pc, sti) emitm_fl_3((pc), emit_b111, emit_b110, (sti)) -# define emitm_fcomi(pc, sti) emitm_fl_3((pc), emit_b011, emit_b110, (sti)) -#else -# define emitm_fcomip(pc, sti) do { \ - emitm_fcomp((pc), (sti)); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - } while (0) -# define emitm_fcomi(pc, sti) do { \ - emitm_fcom((pc), (sti)); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - } while (0) -#endif - -# define emitm_fcompp(pc) { *((pc)++) = (char) 0xde; *((pc)++) = (char) 0xd9; } - -# define emitm_fcom_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b010, (b), (i), (s), (d)) - -# define emitm_fcomp_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b011, (b), (i), (s), (d)) - -/* ST -= real64 */ -# define emitm_fsub_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b100, (b), (i), (s), (d)) - -/* ST -= int32_mem */ -# define emitm_fisub_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b100, (b), (i), (s), (d)) - -# define emitm_fadd_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b000, (b), (i), (s), (d)) - -/* ST += int32_mem */ -# define emitm_fiadd_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b000, (b), (i), (s), (d)) - -/* ST *= real64 */ -# define emitm_fmul_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b001, (b), (i), (s), (d)) - -/* ST *= int32_mem */ -# define emitm_fimul_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b001, (b), (i), (s), (d)) - -/* ST /= real64 */ -# define emitm_fdiv_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b10, 0, emit_b110, (b), (i), (s), (d)) - -/* ST /= int32_mem */ -# define emitm_fidiv_m(interp, pc, b, i, s, d) \ - emitm_fl_2((interp), (pc), emit_b01, 0, emit_b110, (b), (i), (s), (d)) - -/* Ops Needed to support loading EFLAGs for conditional branches */ -# define emitm_fstw(pc) emitm_fl_3((pc), emit_b111, emit_b100, emit_b000) - -# define emitm_sahf(pc) *((pc)++) = (char) 0x9e - -/* misc float */ -# define emitm_ftst(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xE4; } -# define emitm_fprem(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xF8; } -# define emitm_fprem1(pc) { *(pc)++ = 0xd9; *(pc)++ = 0xF5; } - -# define emitm_fldcw(interp, pc, mem) \ - emitm_fl_2((interp), (pc), emit_b00, 1, emit_b101, 0, 0, 0, (mem)) - -#if defined(NEG_MINUS_ZERO) -# define jit_emit_neg_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fchs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_fchs(pc); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } - -#elif defined(NEG_ZERO_SUB) - -# define jit_emit_neg_r_n(pc, r) { \ - emitm_fldz(pc); \ - emitm_fsubrp((pc), ((r)+1)); \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_fldz(pc); \ - emitm_fsubrp((pc), 1); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } -#else - -# define jit_emit_neg_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_ftst(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - emitm_jxs((pc), emitm_jz, 2); \ - emitm_fchs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_neg_M_n(interp, pc, mem) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (mem)); \ - emitm_ftst(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - emitm_jxs((pc), emitm_jz, 2); \ - emitm_fchs(pc); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (mem)); \ - } -#endif - -# define jit_emit_sin_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fsin(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_cos_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fcos(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_sqrt_r_n(pc, r) \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fsqrt(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } - -# define jit_emit_abs_r_n(pc, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - } \ - emitm_fabs(pc); \ - if (r) { \ - emitm_fstp((pc), ((r)+1)); \ - } \ - } - -# define jit_emit_abs_r_i(pc, r) { \ - jit_emit_test_r_i((pc), (r)); \ - emitm_jxs((pc), emitm_jns, 3); \ - jit_emit_not_r_i((pc), (r)); \ - jit_emit_inc_r_i((pc), (r)); \ - } - -# define jit_emit_abs_m_n(interp, pc, mem) { \ - jit_emit_fload_m_n((interp), (pc), (mem)); \ - emitm_fabs(pc); \ - jit_emit_fstore_m_n((pc), (mem)); \ - } - -/* Integer comparisons */ -# define jit_emit_cmp_rr(pc, reg1, reg2) \ - emitm_alul_r_r((pc), 0x39, (reg2), (reg1)) -# define jit_emit_cmp_rr_i(pc, r1, r2) jit_emit_cmp_rr((pc), (r1), (r2)) - -# define emitm_cmpl_r_m(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x3b, (reg), (b), (i), (s), (d)) - -# define emitm_cmpl_m_r(pc, reg, b, i, s, d) \ - emitm_alul_r_m((pc), 0x39, (reg), (b), (i), (s), (d)) - -# define jit_emit_cmp_ri_i(interp, pc, reg, imm) \ - emitm_alul_i_r((pc), 0x81, emit_b111, (imm), (reg)) - -/* Unconditional Jump/Call */ - -# define emitm_call_cfunc(pc, func) emitm_calll((pc), (char *)(func) - (pc) - 4) - -# define emitm_calll(pc, disp) { \ - *((pc)++) = (char) 0xe8; \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_callr(pc, reg) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char) 0xd0 | ((reg) - 1); } - -# define emitm_callm(pc, b, i, s, d) { \ - *((pc)++) = (char) 0xff; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b010), (b), (i), (s), (d)); } - -# define emitm_jumps(pc, disp) { \ - *((pc)++) = (char) 0xeb; \ - *((pc)++) = (disp); } - -# define emitm_jumpl(pc, disp) { \ - *((pc)++) = (char) 0xe9; \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_jumpr(pc, reg) { \ - *((pc)++) = (char) 0xff; \ - *((pc)++) = (char)(0xe0 | ((reg) - 1)); } - -# define emitm_jumpm(pc, b, i, s, d) { \ - *((pc)++) = (char) 0xff; \ - (pc) = emit_r_X((interp), (pc), emit_reg(emit_b100), (b), (i), (s), (d)); } - -/* Conditional jumps */ - -/* Short jump - 8 bit disp */ -# define emitm_jxs(pc, code, disp) { \ - *((pc)++) = (char)(0x70 | (code)); \ - *((pc)++) = (char)(disp); } - -/* Long jump - 32 bit disp */ -# define emitm_jxl(pc, code, disp) { \ - *((pc)++) = (char) 0x0f; \ - *((pc)++) = (char)(0x80 | (code)); \ - *(long *)(pc) = (disp); (pc) += 4; } - -# define emitm_jo 0 -# define emitm_jno 1 -# define emitm_jb 2 -# define emitm_jnb 3 -# define emitm_jz 4 -# define emitm_je emitm_jz -# define emitm_jnz 5 -# define emitm_jne emitm_jnz -# define emitm_jbe 6 -# define emitm_ja 7 -# define emitm_js 8 -# define emitm_jns 9 -# define emitm_jp 10 -# define emitm_jnp 11 -# define emitm_jl 12 -# define emitm_jnl 13 -# define emitm_jle 14 -# define emitm_jg 15 - -/* set byte conditional */ -# define jit_emit_setcc_r(pc, cc, r) \ - *(pc)++ = 0x0f; \ - *(pc)++ = 0x90 + (cc); \ - *(pc)++ = (char) emit_alu_X_r(0, (r)) - -/* - * core.jit interface - * - * The new offset based versions have uppercase RM or MR inside - * That's probably only during transition time - */ - -# define jit_emit_mov_mi_i(pc, dest, immediate) \ - emitm_movl_i_m((pc), (immediate), emit_None, emit_None, emit_None, (dest)) - -# define jit_emit_mov_MI_i(interp, pc, offs, immediate) \ - emitm_movl_i_m((pc), (immediate), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mov_rm_i(interp, pc, reg, address) \ - emitm_movl_m_r((interp), (pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_mov_RM_i(interp, pc, reg, offs) \ - emitm_movl_m_r((interp), (pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mov_mr_i(interp, pc, address, reg) \ - emitm_movl_r_m((interp), (pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_mov_MR_i(interp, pc, offs, reg) \ - emitm_movl_r_m((interp), (pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_mul_RM_i(interp, pc, reg, offs) \ - emitm_smull_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_RM_i(interp, pc, reg, offs) \ - emitm_subl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_MR_i(interp, pc, offs, reg) \ - emitm_subl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_sub_MI_i(pc, offs, imm) \ - emitm_subl_i_m((pc), (imm), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_RM_i(interp, pc, reg, offs) \ - emitm_addl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_MR_i(interp, pc, offs, reg) \ - emitm_addl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_add_MI_i(pc, offs, imm) \ - emitm_addl_i_m((pc), (imm), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_cmp_rm_i(pc, reg, address) \ - emitm_cmpl_r_m((pc), (reg), emit_None, emit_None, emit_None, (address)) - -# define jit_emit_cmp_RM_i(interp, pc, reg, offs) \ - emitm_cmpl_r_m((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -# define jit_emit_cmp_MR_i(interp, pc, offs, reg) \ - emitm_cmpl_m_r((pc), (reg), emit_EBX, emit_None, 1, (offs)) - -/* high level routines, behave like real 2 register FP */ - -/* mapped float registers numbers are ST(1)-ST(4). - * scratch register is ST(0) - */ - -/* ST(i) <- numvar */ -# define jit_emit_mov_RM_n(interp, pc, r, d) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (d)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= NUM_CONST */ -# define jit_emit_mov_ri_n(interp, pc, r, i) { \ - jit_emit_fload_m_n((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= &INT_CONST */ -# define jit_emit_mov_ri_ni(interp, pc, r, i) { \ - jit_emit_fload_m_i((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(i) <= INT_REG */ -# define jit_emit_mov_RM_ni(interp, pc, r, i) { \ - jit_emit_fload_mb_i((interp), (pc), (i)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* NUM_REG(i) <= &INT_CONST - * the int const i is loaded from the code memory - */ -# define jit_emit_mov_MI_ni(interp, pc, offs, i) { \ - jit_emit_fload_m_i((interp), (pc), (i)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -/* INT_REG <= ST(i) */ -# define jit_emit_mov_mr_in(pc, mem, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_m_i((pc), (mem)); \ -} - -/* numvar <- ST(i) */ -# define jit_emit_mov_mr_n(pc, d, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_m_n((pc), (d)); \ -} - -# define jit_emit_mov_MR_n(interp, pc, d, r) { \ - if (r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (d)); \ - } \ - else { \ - jit_emit_fst_mb_n((interp), (pc), emit_EBX, (d)); \ - } \ -} - -/* ST(r1) <= ST(r2) */ -# define jit_emit_mov_rr_n(pc, r1, r2) { \ - if ((r1) != (r2)) { \ - if (r2) { \ - emitm_fld((pc), (r2)); \ - emitm_fstp((pc), ((r1)+1)); \ - } \ - else { \ - emitm_fst((pc), (r1)); \ - } \ - } \ -} - -/* ST(r1) xchg ST(r2) */ -# define jit_emit_xchg_rr_n(interp, pc, r1, r2) { \ - if ((r1) != (r2)) { \ - emitm_fld((pc), (r1)); \ - emitm_fld((pc), ((r2)+1)); \ - emitm_fstp((pc), ((r1)+2)); \ - emitm_fstp((pc), ((r2)+1)); \ - } \ -} - -# define jit_emit_xchg_RM_n(interp, pc, r, offs) { \ - emitm_fld((pc), (r)); \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_fstp((pc), ((r)+2)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -# define jit_emit_xchg_MR_n(interp, pc, offs, r) { \ - emitm_fld((pc), (r)); \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_fstp((pc), ((r)+2)); \ - jit_emit_fstore_mb_n((interp), (pc), emit_EBX, (offs)); \ -} - -# define jit_emit_finit(pc) { *((pc)++) = (char) 0xdb; *((pc)++) = (char) 0xe3; } - -/* ST(i) op= MEM */ - -# define jit_emit_xxx_rm_n(interp, op, pc, r, m) { \ - jit_emit_fload_m_n((interp), (pc), (m)); \ - emitm_f ## op ## p((pc), ((r)+1)); \ -} - -# define jit_emit_xxx_RM_n(interp, op, pc, r, offs) { \ - jit_emit_fload_mb_n((interp), (pc), emit_EBX, (offs)); \ - emitm_f ## op ## p((pc), ((r)+1)); \ -} - -/* - * float ops in two flavors: abs memory for constants, offsets for regs - */ - -# define jit_emit_add_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), add, (pc), (r), (m)) -# define jit_emit_sub_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), sub, (pc), (r), (m)) -# define jit_emit_mul_ri_n(interp, pc, r, m) jit_emit_xxx_rm_n((interp), mul, (pc), (r), (m)) - -# define jit_emit_add_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), add, (pc), (r), (o)) -# define jit_emit_sub_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), sub, (pc), (r), (o)) -# define jit_emit_mul_RM_n(interp, pc, r, o) jit_emit_xxx_RM_n((interp), mul, (pc), (r), (o)) - -/* ST(r1) += ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) + ST(i) - * r2 == 0: ST(i) <- ST(0) + ST(i) - */ -# define jit_emit_add_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fadd((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_faddr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_faddp((pc), ((r1)+1)); \ - } \ - } \ - while (0) -/* - * ST(r) += INT_REG - */ -# define jit_emit_add_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fiadd_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* ST(r1) -= ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) - ST(i) - * r2 == 0: ST(i) <- ST(i) - ST(0) - */ -# define jit_emit_sub_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fsub((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_fsubr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_fsubp((pc), ((r1)+1)); \ - } \ - } \ - while (0) - -/* - * ST(r) -= INT_REG - */ -# define jit_emit_sub_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fisub_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -# define jit_emit_inc_r_n(pc, r) { \ - emitm_fld1(pc); \ - emitm_faddp((pc), ((r)+1)); \ -} - -# define jit_emit_dec_r_n(pc, r) { \ - emitm_fld1(pc); \ - emitm_fsubp((pc), ((r)+1)); \ -} - -/* ST(r1) *= ST(r2) */ -/* r1 == 0: ST(0) <- ST(0) * ST(i) - * r2 == 0: ST(i) <- ST(0) * ST(i) - */ -# define jit_emit_mul_rr_n(interp, pc, r1, r2) do { \ - if (!(r1)) { \ - emitm_fmul((pc), (r2)); \ - } \ - else if (!(r2)) { \ - emitm_fmulr((pc), (r1)); \ - } \ - else { \ - emitm_fld((pc), (r2)); \ - emitm_fmulp((pc), ((r1)+1)); \ - } \ - } \ - while (0) - -/* - * ST(r) *= INT_REG - */ -# define jit_emit_mul_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fimul_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* - * ST(r) /= INT_REG - */ -# define jit_emit_div_RM_ni(pc, r, offs) { \ - emitm_fld((pc), (r)); \ - emitm_fidiv_m((pc), emit_EBX, 0, 1, (offs)); \ - emitm_fstp((pc), ((r)+1)); \ -} - -/* test r for zero */ -# define jit_emit_test_r_n(pc, r) { \ - if (r) { \ - emitm_fxch((pc), (r)); \ - } \ - emitm_fxam(pc); \ - emitm_fstw(pc); \ - emitm_sahf(pc); \ - if (r) { \ - emitm_fxch((pc), (r)); \ - } \ -} - -enum { JIT_X86BRANCH, JIT_X86JUMP, JIT_X86CALL }; - -# define jit_emit_stack_frame_enter(pc) do { \ - emitm_pushl_r((pc), emit_EBP); \ - jit_emit_mov_rr_i((pc), emit_EBP, emit_ESP); \ -} while (0) - -# define jit_emit_stack_frame_leave(pc) do { \ - jit_emit_mov_rr_i((pc), emit_ESP, emit_EBP); \ - emitm_popl_r((pc), emit_EBP); \ -} while (0) - -# define jit_emit_end(pc) { \ - jit_emit_add_ri_i((interp), (pc), emit_ESP, 4); \ - emitm_popl_r((pc), emit_EDI); \ - emitm_popl_r((pc), emit_ESI); \ - emitm_popl_r((pc), emit_EBX); \ - emitm_popl_r((pc), emit_EBP); \ - emitm_ret(pc); \ - } - -size_t calc_signature_needs(const char *sig, int *strings); - -void * Parrot_jit_build_call_func(PARROT_INTERP, PMC *pmc_nci, - STRING *signature, int *sizeptr); - -/* - * register usage - * %edi, %esi ... mapped, preserved - * %edx, %ecx ... mapped, not preserved - * %ebx ... base pointer for register access, preserved - * %eax ... scratch, return value register - */ - -#endif /* PARROT_I386_JIT_EMIT_H_GUARD */ +#endif /* PARROT_FRAME_BUILDER_H_GUARD */ /* * Local variables: diff --git a/src/nci_test.c b/src/nci_test.c index 2044d9d..f1c972e 100644 --- a/src/nci_test.c +++ b/src/nci_test.c @@ -110,6 +110,8 @@ PARROT_DYNEXT_EXPORT char * nci_ttt(char *, char *); PARROT_DYNEXT_EXPORT void nci_vfff(float, float, float); PARROT_DYNEXT_EXPORT void nci_vV(const char **); PARROT_DYNEXT_EXPORT void nci_vVVV(const char **, const char **, const char **); +PARROT_DYNEXT_EXPORT int nci_i20(int, int, int, int, int, int, int, int, int, int, int, int, + int, int, int, int, int, int, int); /* Declarations for callback tests */ @@ -1191,6 +1193,50 @@ nci_vVVV(const char **ptr1, const char **ptr2, const char **ptr3) *ptr3 = "Go suck a lemon.\n"; } +/* + +=item C + +Prints and returns the nth value in a list of integers. First argument is the selector; subsequents, +the list. + +This function is designed to be outside of the range of the static frame builder as an excercise for +the dynamic frame builder. + +=cut + +*/ +PARROT_DYNEXT_EXPORT int +nci_i20(int sel, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int v9, int v10, + int v11, int v12, int v13, int v14, int v15, int v16, int v17, int v18) { + int *selected; + switch ((sel < 0 ? -sel : sel) % 18) { + case 0: selected = &v1; break; + case 1: selected = &v2; break; + case 2: selected = &v3; break; + case 3: selected = &v4; break; + case 4: selected = &v5; break; + case 5: selected = &v6; break; + case 6: selected = &v7; break; + case 7: selected = &v8; break; + case 8: selected = &v9; break; + case 9: selected = &v10; break; + case 10: selected = &v11; break; + case 11: selected = &v12; break; + case 12: selected = &v13; break; + case 13: selected = &v14; break; + case 14: selected = &v15; break; + case 15: selected = &v16; break; + case 16: selected = &v17; break; + case 17: selected = &v18; break; + default: printf("default case reached (should never happen)"); return -1; + } + printf("%d\n", *selected); + return *selected; +} + #ifdef TEST char l2 = 4; diff --git a/src/ops/core.ops b/src/ops/core.ops index 0b78166..eae4b8d 100644 --- a/src/ops/core.ops +++ b/src/ops/core.ops @@ -1322,7 +1322,6 @@ op dlfunc(out PMC, invar PMC, in STR, in STR) { else { $1 = pmc_new(interp, enum_class_NCI); VTABLE_set_pointer_keyed_str(interp, $1, $4, F2DPTR(p)); - PObj_get_FLAGS($1) |= PObj_private1_FLAG; } Parrot_str_free_cstring(name); } diff --git a/src/pmc/nci.pmc b/src/pmc/nci.pmc index ef5c5e4..9da11e8 100644 --- a/src/pmc/nci.pmc +++ b/src/pmc/nci.pmc @@ -18,86 +18,116 @@ The vtable functions for the native C call functions. */ +#include "parrot/nci.h" + typedef INTVAL (*nci_sub_t)(PARROT_INTERP, PMC *); -typedef INTVAL (*nci_jit_sub_t)(PARROT_INTERP, PMC *, char *); - -void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI_attributes * const nci_info, - size_t sig_length); -void pcc_params(PARROT_INTERP, STRING *sig, Parrot_NCI_attributes * const nci_info, - size_t sig_length) { - char param_buf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - char *param_sig = sig_length <= 7 - ? param_buf - : mem_allocate_n_typed(sig_length, char); - size_t j = 0; - size_t i; - - for (i = 1; i < sig_length; i++) { - INTVAL c = Parrot_str_indexed(interp, sig, i); +typedef nci_sub_t nci_jit_sub_t; - switch (c) { - case (INTVAL)'0': /* null ptr or such - doesn't consume a reg */ - break; - case (INTVAL)'f': - case (INTVAL)'N': - case (INTVAL)'d': - param_sig[j++] = 'N'; - break; - case (INTVAL)'I': /* INTVAL */ - case (INTVAL)'l': /* long */ - case (INTVAL)'i': /* int */ - case (INTVAL)'s': /* short */ - case (INTVAL)'c': /* char */ - param_sig[j++] = 'I'; - break; - case (INTVAL)'S': - case (INTVAL)'t': /* string, pass a cstring */ - param_sig[j++] = 'S'; - break; - case (INTVAL)'J': /* interpreter */ - break; - case (INTVAL)'p': /* push pmc->data */ - case (INTVAL)'O': /* push PMC * object in P2 */ - case (INTVAL)'P': /* push PMC * */ - case (INTVAL)'V': /* push PMC * */ - param_sig[j++] = 'P'; - case (INTVAL)'v': - break; - /* I have no idea how to handle these */ - case (INTVAL)'2': - case (INTVAL)'3': - case (INTVAL)'4': - param_sig[j++] = 'I'; - break; - case (INTVAL)'@': - param_sig[j++] = '@'; - break; - case (INTVAL)'b': /* buffer (void*) pass Buffer_bufstart(SReg) */ - case (INTVAL)'B': /* buffer (void**) pass &Buffer_bufstart(SReg) */ - param_sig[j++] = 'S'; - break; - default: - if (sig_length > 7) - mem_sys_free(param_sig); - Parrot_ex_throw_from_c_args(interp, NULL, +#define NCI_raw_FLAG PObj_private0_FLAG + +STRING *pcc_sig_params(PARROT_INTERP, STRING *sig); +STRING *pcc_sig_params(PARROT_INTERP, STRING *sig) { + size_t sig_len = Parrot_str_byte_length(interp, sig); + char param_buf[sig_len*2]; + + size_t i, j; + + for (i = 1, j = 0; i < sig_len; i++) { + INTVAL c = Parrot_str_indexed(interp, sig, i); + if (c > 127) { + Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_JIT_ERROR, - "Unknown param Signature %c\n", (char)c); - break; + "Unknown param type at %d in signature '%S' (way too big)\n", i, sig); + } + else { + switch ((char)c) { + case 'v': + case '0': + case 'J': + break; + case 'N': + case 'd': + case 'f': + param_buf[j++] = 'N'; + break; + case 'I': + case 'l': + case 'i': + case 's': + case 'c': + param_buf[j++] = 'I'; + break; + case 'S': + case 't': + case 'b': + case 'B': + param_buf[j++] = 'S'; + break; + case 'P': + case 'p': + case 'V': + case '2': + case '3': + case '4': + param_buf[j++] = 'P'; + break; + case 'O': + param_buf[j++] = 'P'; + param_buf[j++] = 'i'; + break; + case '@': + param_buf[j++] = 'P'; + param_buf[j++] = 's'; + break; + default: + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown param type at %d in signature '%S'\n", i, sig); + } } } - PARROT_ASSERT(j <= sig_length); + return string_make(interp, param_buf, j, NULL, PObj_constant_FLAG); +} - /* use only the signature-significant part of the string buffer */ - if (j) { - nci_info->pcc_params_signature = string_make(interp, param_sig, j, - NULL, PObj_constant_FLAG); +STRING *pcc_sig_ret(PARROT_INTERP, STRING *sig); +STRING *pcc_sig_ret(PARROT_INTERP, STRING *sig) { + INTVAL c = Parrot_str_indexed(interp, sig, 0); + if (c > 127) { + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown return type at %d in signature '%S' (way too big)\n", 0, sig); + } + else { + switch ((char)c) { + case 'v': + return CONST_STRING(interp, "v"); + case 'N': + case 'f': + case 'd': + return CONST_STRING(interp, "N"); + case 'I': + case 'l': + case 'i': + case 's': + case 'c': + return CONST_STRING(interp, "I"); + case 'S': + case 't': + return CONST_STRING(interp, "S"); + case 'p': + case 'P': + return CONST_STRING(interp, "P"); + case '2': + case '3': + case '4': + return CONST_STRING(interp, "P"); + default: + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_JIT_ERROR, + "Unknown return type at %d in signature '%S'\n", 0, sig); + } } - else - nci_info->pcc_params_signature = CONST_STRING(interp, ""); - - if (sig_length > 7) - mem_sys_free(param_sig); } /* actually build the NCI thunk */ @@ -106,33 +136,31 @@ static nci_sub_t build_func(PARROT_INTERP, PMC *, Parrot_NCI_attributes *); static nci_sub_t build_func(PARROT_INTERP, PMC *pmc, Parrot_NCI_attributes *nci_info) { - STRING *key = nci_info->signature; - size_t key_length = Parrot_str_byte_length(interp, key); + STRING *key = nci_info->nci_signature; int jitted = 0; - pcc_params(interp, key, nci_info, key_length); - - /* Arity is length of that string minus one (the return type). */ - nci_info->arity = key_length - 1; - /* Build call function. */ nci_info->func = (PMC *)(build_call_func(interp, pmc, key, &jitted)); - nci_info->jitted = jitted; return (nci_sub_t)nci_info->func; } pmclass NCI auto_attrs { - ATTR STRING *signature; /* The signature. */ - ATTR void *func; /* Function pointer to call. */ - ATTR void *orig_func; /* Function pointer - * used to create func */ - ATTR STRING *pcc_params_signature; /* The signature. */ - ATTR STRING *long_signature; /* The full signature. */ - ATTR PMC *multi_sig; /* type tuple array (?) */ - ATTR INTVAL arity; /* Cached arity of the NCI. */ - ATTR INTVAL jitted; /* Is this a jitted NCI stub. */ + /* Signature Attributes */ + ATTR STRING *nci_signature; /* The NCI signature */ + ATTR STRING *pcc_signature_ret; /* The PCC return signature */ + ATTR STRING *pcc_signature_param; /* The PCC param signature */ + + /* Function Pointers */ + ATTR void *func; /* Function pointer to call */ + ATTR void *orig_func; /* Function pointer being wrapped */ + + /* Sub PMC Attributes */ + ATTR INTVAL arity; /* Number of params taken */ + /* MMD Attributes */ + ATTR PMC *multi_sig; + ATTR STRING *long_signature; /* @@ -147,8 +175,9 @@ Return the MMD signature PMC, if any or a Null PMC. METHOD get_multisig() { PMC *sig; GET_ATTR_multi_sig(INTERP, SELF, sig); - if (PMC_IS_NULL(sig)) + if (sig == NULL) { sig = PMCNULL; + } RETURN(PMC *sig); } @@ -178,15 +207,19 @@ Initializes the NCI with a C function pointer. VTABLE void init() { /* Mark that we're not a raw NCI. */ - PObj_flag_CLEAR(private2, SELF); + PObj_get_FLAGS(SELF) &= ~NCI_raw_FLAG; + /* Mark that we have a custom gc marker */ PObj_custom_mark_SET(SELF); } /* -=item C +=item C -Sets the specified function pointer and signature (C<*key>). +=item C + +Get/Set the pointer being wrapped. Setting through this interface sets +the raw flag. =cut @@ -194,29 +227,57 @@ Sets the specified function pointer and signature (C<*key>). VTABLE void set_pointer(void *ptr) { SET_ATTR_orig_func(INTERP, SELF, ptr); - PObj_flag_SET(private2, SELF); + PObj_get_FLAGS(SELF) |= NCI_raw_FLAG; } VTABLE void *get_pointer() { return PARROT_NCI(SELF)->orig_func; } +/* + +=item C + +Roughly equivalent to C and C. +Setting through this interface clears the raw flag. + +=cut + +*/ + VTABLE void set_pointer_keyed_str(STRING *key, void *func) { - Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); - - /* Store the original function and signature. */ - SET_ATTR_orig_func(INTERP, SELF, func); - - /* ensure that the STRING signature is constant */ - if (!PObj_constant_TEST(key)) { - char * const key_c = Parrot_str_to_cstring(INTERP, key); - size_t key_length = Parrot_str_byte_length(interp, key); - key = string_make(interp, key_c, key_length, - NULL, PObj_constant_FLAG); - Parrot_str_free_cstring(key_c); + SELF.set_string_native(key); + SELF.set_pointer(func); + PObj_get_FLAGS(SELF) &= ~NCI_raw_FLAG; + } + +/* + +=item C + +=item C + +Get/Set the NCI signature. + +=cut + +*/ + + VTABLE STRING *get_string() { + return PARROT_NCI(SELF)->nci_signature; + } + + VTABLE void set_string_native(STRING *str) { + if (!PObj_constant_TEST(str)) { + str = Parrot_str_copy(INTERP, str); } + SET_ATTR_nci_signature(INTERP, SELF, str); - nci_info->signature = key; + /* set up derivative attributes */ + SET_ATTR_pcc_signature_param(INTERP, SELF, pcc_sig_params(INTERP, str)); + SET_ATTR_pcc_signature_ret(INTERP, SELF, pcc_sig_ret(INTERP, str)); + /* Arity is length of the NCI signature minus one (the return type). */ + SET_ATTR_arity(INTERP, SELF, Parrot_str_byte_length(INTERP, str) - 1); } /* @@ -232,8 +293,9 @@ Mark any referenced strings and PMCs. if (PARROT_NCI(SELF)) { Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); - Parrot_gc_mark_STRING_alive(interp, nci_info->signature); - Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_params_signature); + Parrot_gc_mark_STRING_alive(interp, nci_info->nci_signature); + Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_signature_param); + Parrot_gc_mark_STRING_alive(interp, nci_info->pcc_signature_ret); Parrot_gc_mark_STRING_alive(interp, nci_info->long_signature); Parrot_gc_mark_PMC_alive(interp, nci_info->multi_sig); } @@ -262,11 +324,13 @@ Creates and returns a clone of the NCI. * ManagedStruct or Buffer? */ nci_info_ret->func = nci_info_self->func; - nci_info_ret->orig_func = nci_info_self->orig_func; - nci_info_ret->signature = nci_info_self->signature; - nci_info_ret->pcc_params_signature = nci_info_self->pcc_params_signature; + nci_info_ret->orig_func = nci_info_self->orig_func; + nci_info_ret->nci_signature = nci_info_self->nci_signature; + nci_info_ret->pcc_signature_param = nci_info_self->pcc_signature_param; + nci_info_ret->pcc_signature_ret = nci_info_self->pcc_signature_ret; + nci_info_ret->long_signature = nci_info_self->long_signature; + nci_info_ret->multi_sig = nci_info_self->multi_sig; nci_info_ret->arity = nci_info_self->arity; - nci_info_ret->jitted = nci_info_self->jitted; PObj_get_FLAGS(ret) |= (PObj_get_FLAGS(SELF) & 0x7); return ret; @@ -306,7 +370,7 @@ class, the PMC arguments are shifted down. PMC *cont; GET_ATTR_orig_func(INTERP, SELF, orig_func); - func = PObj_flag_TEST(private2, SELF) + func = PObj_get_FLAGS(SELF) & NCI_raw_FLAG ? (nci_sub_t) D2FPTR(orig_func) : (nci_sub_t) D2FPTR(nci_info->func); @@ -320,23 +384,8 @@ class, the PMC arguments are shifted down. "attempt to call NULL function"); } - if (nci_info->jitted) { - nci_jit_sub_t jit_func = (nci_jit_sub_t) D2FPTR(nci_info->func); + func(INTERP, SELF); - /* Parrot_eprintf(interp, "JITTED %S\n", nci_info->signature); */ - sig_str = Parrot_str_to_cstring(interp, nci_info->pcc_params_signature); - jit_func(INTERP, SELF, sig_str); - Parrot_str_free_cstring(sig_str); - } - else { - if (PObj_flag_TEST(private2, SELF)) { - /* Parrot_eprintf(interp, "RAW NCI CALL\n"); */ - } - else { - /* Parrot_eprintf(interp, "HACKED %S\n", nci_info->signature); */ - } - func(INTERP, SELF); - } cont = INTERP->current_cont; /* @@ -397,21 +446,84 @@ Return the arity of the NCI (the number of arguments). */ METHOD arity() { - Parrot_NCI_attributes * const nci_info = PARROT_NCI(SELF); - INTVAL arity = 0; - - if (nci_info) { - if (!nci_info->func) - build_func(INTERP, SELF, nci_info); - if (nci_info->func) { - arity = nci_info->arity; - RETURN(INTVAL arity); - } + INTVAL arity; + GET_ATTR_arity(INTERP, SELF, arity); + RETURN(INTVAL arity); + } + +/* + +=item C + +=item C + +=item C + +Accessors for all attributes of this class not otherwise accessible through VTABLES. +Integers are used for keys to make access easier for JIT. These are also available to +PIR from F + +=over + +=item INTVAL keys + +C + +=item STRING keys + +C, C, +C + +=item PMC keys + +C + +=back + +=cut + +*/ + + VTABLE INTVAL get_integer_keyed_int(INTVAL key) { + switch (key) { + case PARROT_NCI_ARITY: + return PARROT_NCI(SELF)->arity; + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_integer_keyed_int()"); + } + } + + VTABLE STRING *get_string_keyed_int(INTVAL key) { + switch (key) { + case PARROT_NCI_PCC_SIGNATURE_PARAMS: + return PARROT_NCI(SELF)->pcc_signature_param; + case PARROT_NCI_PCC_SIGNATURE_RET: + return PARROT_NCI(SELF)->pcc_signature_ret; + case PARROT_NCI_LONG_SIGNATURE: + return PARROT_NCI(SELF)->long_signature; + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_string_keyed_int()"); } + } - Parrot_ex_throw_from_c_args(INTERP, NULL, - EXCEPTION_INVALID_OPERATION, - "You cannot get the arity of an undefined NCI."); + VTABLE PMC *get_pmc_keyed_int(INTVAL key) { + PMC *retval; + switch (key) { + case PARROT_NCI_MULTI_SIG: + GET_ATTR_multi_sig(INTERP, SELF, retval); + default: + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, + "Bad index for NCI.get_pmc_keyed_int()"); + } + if (retval == NULL) { + retval = PMCNULL; + } + return retval; } } diff --git a/t/pmc/nci.t b/t/pmc/nci.t index 735f152..667da34 100644 --- a/t/pmc/nci.t +++ b/t/pmc/nci.t @@ -5,8 +5,19 @@ use strict; use warnings; use lib qw( . lib ../lib ../../lib ); +use Parrot::BuildUtil; +use Parrot::NativeCall 'signature_nci_to_pcc'; + +my @nci_sigs; +BEGIN { + @nci_sigs = + grep {$_} + map {chomp; s/^\s*//; s/\s*$//; s/#.*$//; $_} + split /\n/, Parrot::BuildUtil::slurp_file('src/call_list.txt'); +} + use Test::More; -use Parrot::Test tests => 70; +use Parrot::Test tests => (71 + @nci_sigs); use Parrot::Config qw(%PConfig); =head1 NAME @@ -32,6 +43,27 @@ Most tests are skipped when the F shared library is not found. $ENV{TEST_PROG_ARGS} ||= ''; +foreach my $nci_sig (@nci_sigs) { + my ($nci_ret, $nci_params) = $nci_sig =~ /\S+/g; + $nci_params ||= ''; + my $pcc_sig = signature_nci_to_pcc($nci_sig); + pir_output_is( << "CODE", "$pcc_sig\n", "NCI PMC signatures equivalent to nativecall.pl ('$nci_sig')" ); +.include "nci.pasm" +.sub test :main + .local pmc nci + nci = new ['NCI'] + nci = "${nci_ret}${nci_params}" + .local string s + s = nci[ .PARROT_NCI_PCC_SIGNATURE_PARAMS ] + print s + print "->" + s = nci[ .PARROT_NCI_PCC_SIGNATURE_RET ] + print s + print "\\n" +.end +CODE +} + SKIP: { unless ( -e "runtime/parrot/dynext/libnci_test$PConfig{load_ext}" ) { skip( "Please make libnci_test$PConfig{load_ext}", Test::Builder->expected_tests() ); @@ -2753,6 +2785,76 @@ It is a beautiful day! Go suck a lemon. OUTPUT +my $test_code = <<'CODE'; +.sub test :main + .local pmc libnci_test + $S0 = 'libnci_test' + libnci_test = loadlib $S0 + + .local pmc nci_i20 + nci_i20 = dlfunc libnci_test, "nci_i20", "iiiiiiiiiiiiiiiiiiii" + + .local pmc args + args = new ['FixedIntegerArray'] + args = 18 + + $I0 = 2 + args[0] = 1 + args[1] = 1 + +LOOP1: + $I1 = $I0 - 1 + $I1 = args[$I1] + + $I2 = $I0 - 2 + $I2 = args[$I2] + + $I3 = $I1 + $I2 + args[$I0] = $I3 + inc $I0 + if $I0 < 18 goto LOOP1 + + $I0 = args + dec $I0 + + $I1 = args[0] + $I2 = args[1] + $I3 = args[2] + $I4 = args[3] + $I5 = args[4] + $I6 = args[5] + $I7 = args[6] + $I8 = args[7] + $I9 = args[8] + $I10 = args[9] + $I11 = args[10] + $I12 = args[11] + $I13 = args[12] + $I14 = args[13] + $I15 = args[14] + $I16 = args[15] + $I17 = args[16] + $I18 = args[17] + +LOOP2: + nci_i20($I0, $I1, $I2, $I3, $I4, $I5, $I6, $I7, $I8, $I9, $I10, $I11, $I12, $I13, $I14, $I15, $I16, $I17, $I18) + $I0 = $I0 / 2 + if $I0 > 0 goto LOOP2 +.end +CODE +if ($PConfig{cc_build_call_frames}) { + pir_output_is($test_code, < 27; +use Test::More tests => 28; use lib qw( lib t/configure/testlib ); use_ok('config::init::defaults'); use_ok('config::auto::frames'); @@ -33,22 +33,24 @@ $conf->add_steps($pkg); $conf->options->set( %{$args} ); my $step = test_step_constructor_and_description($conf); -# To avoid a warning about an unitialized value, we will set nvsize to 8, -# cpuarch to i386 and osname to linux. +# To avoid a warning about an uninitialized value, we will set osname to linux. # This is normally done during earlier configuration steps. -$conf->data->set( nvsize => 8 ); -$conf->data->set( cpuarch => 'i386' ); $conf->data->set( osname => 'linux' ); +$conf->data->set( HAS_LIBJIT => 1 ); my $ret = $step->runstep($conf); ok( $ret, "runstep() returned true value" ); ok( defined ( $step->result() ), "Got defined result" ); -TODO: { - local $TODO = - 'build frames temporarily disabled at pcc_reapply merge: TT #1132'; - is( $step->result(), 'yes', "Result is 'yes', as expected" ); -} +is( $step->result(), 'yes', "Result is 'yes', as expected" ); + +$conf->data->set( HAS_LIBJIT => undef ); +$ret = $step->runstep($conf); +ok( $ret, "runstep() returned true value" ); +ok( defined ( $step->result() ), + "Got defined result" ); +is( $step->result(), 'no', "Result is 'no', as expected" ); + $conf->cc_clean(); $step->set_result( undef ); @@ -68,46 +70,20 @@ $can_build_call_frames = auto::frames::_call_frames_buildable($conf); ok( ! $can_build_call_frames, "_call_frames_buildable() returned false value, as expected" ); +$conf->data->set( HAS_LIBJIT => 1 ); $conf->options->set( buildframes => undef ); -$conf->data->set( osname => 'linux' ); -$conf->data->set( cpuarch => 'i386' ); -$conf->data->set( nvsize => 8 ); -$can_build_call_frames = auto::frames::_call_frames_buildable($conf); -TODO: { - local $TODO = - 'build frames temporarily disabled at pcc_reapply merge: TT #1132'; - ok( $can_build_call_frames, - "_call_frames_buildable() returned true value, as expected (i386/non darwin/8)" - ); -} - -$conf->data->set( osname => 'darwin' ); -$conf->data->set( cpuarch => 'i386' ); -$conf->data->set( nvsize => 8 ); -$can_build_call_frames = auto::frames::_call_frames_buildable($conf); -ok( ! $can_build_call_frames, - "_call_frames_buildable() returned false value, as expected (i386/darwin/8)" ); - -$conf->data->set( osname => 'linux' ); -$conf->data->set( cpuarch => 'ppc' ); -$conf->data->set( nvsize => 8 ); $can_build_call_frames = auto::frames::_call_frames_buildable($conf); -ok( ! $can_build_call_frames, - "_call_frames_buildable() returned false value, as expected (ppc/linux/8)" ); +ok( $can_build_call_frames, + "_call_frames_buildable() returned true value, as expected" ); -$conf->data->set( osname => 'linux' ); -$conf->data->set( cpuarch => 'i386' ); -$conf->data->set( nvsize => 4 ); +$conf->data->set( HAS_LIBJIT => undef ); +$conf->options->set( buildframes => 0 ); $can_build_call_frames = auto::frames::_call_frames_buildable($conf); ok( ! $can_build_call_frames, - "_call_frames_buildable() returned false value, as expected (i386/linux/4)" ); + "_call_frames_buildable() returned false value, as expected" ); ##### _handle_call_frames_buildable() ##### -$conf->data->set( nvsize => 8 ); -$conf->data->set( cpuarch => 'i386' ); -$conf->data->set( osname => 'linux' ); - my $rv; $can_build_call_frames = 0; @@ -123,19 +99,16 @@ $conf->data->set( 'cc_build_call_frames' => undef ); $conf->data->set( 'has_exec_protect' => undef ); $can_build_call_frames = 1; -my $realos = $conf->data->get( 'osname' ); -$conf->data->set( 'osname' => 'foobar' ); $rv = $step->_handle_can_build_call_frames( $conf, $can_build_call_frames ); ok( $rv, "_handle_can_build_call_frames() returned true value" ); is( $conf->data->get( 'cc_build_call_frames'), '-DCAN_BUILD_CALL_FRAMES', "cc_build_call_frames set to expected value" ); -is( $conf->data->get( 'has_exec_protect' ), 0, - "has_exec_protect is 0, as expected" ); +is( $conf->data->get( 'has_exec_protect' ), 1, + "has_exec_protect is 1, as expected" ); is( $step->result(), 'yes', "Result is 'yes', as expected" ); $conf->data->set( 'cc_build_call_frames' => undef ); $conf->data->set( 'has_exec_protect' => undef ); -$conf->data->set( 'osname' => $realos ); pass("Completed all tests in $0"); diff --git a/t/steps/auto/libjit-01.t b/t/steps/auto/libjit-01.t new file mode 100644 index 0000000..004dc6e --- /dev/null +++ b/t/steps/auto/libjit-01.t @@ -0,0 +1,173 @@ +#! perl +# Copyright (C) 2009, Parrot Foundation. +# $Id$ +# auto/libjit-01.t + +use strict; +use warnings; + +use Test::More tests => 34; +use lib qw( lib t/configure/testlib ); +use Parrot::Configure; +use Parrot::Configure::Options 'process_options'; +use Parrot::Configure::Test qw( + test_step_thru_runstep + rerun_defaults_for_testing + test_step_constructor_and_description +); +use IO::CaptureOutput qw( capture ); + +use_ok('config::init::defaults'); +use_ok('config::auto::libjit'); + +my ($args, $step_list_ref) = process_options( { + argv => [ q{--without-libjit} ], + mode => 'configure', +} ); + +my $conf = Parrot::Configure->new; + +my $serialized = $conf->pcfreeze(); + +test_step_thru_runstep( $conf, 'init::defaults', $args ); + +my $pkg = 'auto::libjit'; +my ( $step, $ret ); + +$conf->add_steps($pkg); +$conf->options->set(%$args); +$step = test_step_constructor_and_description($conf); +$ret = $step->runstep($conf); +ok( $ret, "runstep() returned true value" ); +is( $step->result(), 'no', "Result is 'no', as expected" ); +is( $conf->data->get( 'HAS_LIBJIT' ), 0, + "Got expected result with --without-libjit option" ); +$conf->cc_clean(); + +$conf->replenish($serialized); + +($args, $step_list_ref) = process_options( { + argv => [ ], + mode => q{configure}, +} ); +rerun_defaults_for_testing($conf, $args ); +$conf->add_steps($pkg); +$conf->options->set( %{$args} ); +$step = test_step_constructor_and_description($conf); +$ret = $step->runstep($conf); +ok( $ret, "runstep() returned true value" ); +like( $step->result(), qr/yes|no/, "Result is either 'yes' or 'no'" ); +ok( defined( $conf->data->get( 'HAS_LIBJIT' ) ), + "'HAS_LIBJIT' has defined value" ); +$conf->cc_clean(); + +########## _evaluate_cc_run ########## + +my ($test, $has_libjit, $verbose); + +$step->set_result( undef ); + +$test = q{USES INTERPRETER: 33}; +$has_libjit = 0; +$verbose = 0; +$has_libjit = $step->_evaluate_cc_run($test, $has_libjit, $verbose); +ok( $has_libjit, "_evaluate_cc_run() returned true value, as expected" ); +is( $step->result(), 'yes', "result is yes, as expected" ); + +$step->set_result( undef ); + +$test = q{foobar}; +$has_libjit = 0; +$verbose = 0; +$has_libjit = $step->_evaluate_cc_run($test, $has_libjit, $verbose); +ok( ! $has_libjit, "_evaluate_cc_run() returned false value, as expected" ); +ok( ! defined($step->result()), "result is undefined, as expected" ); + +$step->set_result( undef ); + +$test = q{USES INTERPRETER: 33}; +$has_libjit = 0; +$verbose = 1; +{ + my ($stdout, $stderr); + capture( + sub { $has_libjit = + $step->_evaluate_cc_run($test, $has_libjit, $verbose); }, + \$stdout, + \$stderr, + ); + ok( $has_libjit, "_evaluate_cc_run() returned true value, as expected" ); + is( $step->result(), 'yes', "result is yes, as expected" ); + like( $stdout, qr/\(yes\)/, "Got expected verbose output" ); +} + +########## _handle_has_libjit() ########## + +my $extra_libs; + +$conf->data->set( 'libjit_has_alloca' => undef ); +$conf->data->set( 'libs' => '' ); + +$has_libjit = 1; +$extra_libs = 'mylibs'; +$conf->data->set( 'cpuarch' => 'i386' ); + +auto::libjit::_handle_has_libjit($conf, $has_libjit, $extra_libs); +ok( $conf->data->get( 'libjit_has_alloca'), + "on i386 with libJIT, 'libjit_has_alloca' has true value" ); +is( $conf->data->get( 'libs' ), " $extra_libs", + "Got expected value for libs" ); + +$conf->data->set( 'libjit_has_alloca' => undef ); +$conf->data->set( 'libs' => '' ); + +$has_libjit = 1; +$extra_libs = 'mylibs'; +$conf->data->set( 'cpuarch' => 'ppc' ); + +auto::libjit::_handle_has_libjit($conf, $has_libjit, $extra_libs); +ok( ! $conf->data->get( 'libjit_has_alloca'), + "on non-i386 with libJIT, 'libjit_has_alloca' has false value" ); +is( $conf->data->get( 'libs' ), " $extra_libs", + "Got expected value for libs" ); + +$conf->data->set( 'libjit_has_alloca' => undef ); +$conf->data->set( 'libs' => '' ); + +$has_libjit = 0; +$extra_libs = 'mylibs'; + +auto::libjit::_handle_has_libjit($conf, $has_libjit, $extra_libs); +ok( ! $conf->data->get( 'libjit_has_alloca'), + "without libJIT, 'libjit_has_alloca' has false value" ); +is( $conf->data->get( 'libs' ), "", + "Got expected value for libs" ); + +################### DOCUMENTATION ################### + +=head1 NAME + +auto/libjit-01.t - test auto::libjit + +=head1 SYNOPSIS + + % prove t/steps/auto/libjit-01.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F. + +The tests in this file test auto::libjit. + +=head1 SEE ALSO + +config::auto::libjit, F. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/t/steps/gen/libjit-01.t b/t/steps/gen/libjit-01.t new file mode 100644 index 0000000..92193cf --- /dev/null +++ b/t/steps/gen/libjit-01.t @@ -0,0 +1,112 @@ +#! perl +# Copyright (C) 2009, Parrot Foundation. +# $Id$ +# gen/libjit-01.t + +use strict; +use warnings; + +use constant NUM_GENERATED_FILES => 2; +# use Test::More tests => 8 + 2*NUM_GENERATED_FILES; +use Test::More qw( no_plan ); + +use File::Copy 'move'; +use File::Temp 'tempfile'; + +use lib 'lib'; +use Parrot::Configure; +use Parrot::Configure::Options 'process_options'; +use Parrot::Configure::Test qw( + test_step_thru_runstep + rerun_defaults_for_testing + test_step_constructor_and_description +); + +use_ok('config::gen::libjit'); + +my ($args, $step_list_ref) = process_options( + { + argv => [], + mode => 'configure', + } +); + +my $conf = Parrot::Configure->new; + +my $serialized = $conf->pcfreeze(); + +my $pkg = 'gen::libjit'; +$conf->add_steps($pkg); +$conf->options->set( %$args ); +my $step = test_step_constructor_and_description($conf); + +is( scalar keys %{$step->{targets}}, NUM_GENERATED_FILES, + "Expected number of generated files"); +is_deeply([keys %{$step->{targets}}], [keys %{$step->{templates}}], + "Templates match targets"); + +foreach (keys %{$step->{templates}}) { + ok(-f $step->{templates}{$_}, "Able to locate $_ template") +} + +my %orig_files; +foreach (keys %{$step->{targets}}) { + if (-f (my $targ_name = $step->{targets}{$_})) { + $orig_files{$_} = tempfile(); + move($targ_name, $orig_files{$_}); + } +} + +my %orig_conf = map { $_ => $conf->data->get($_) } qw[ iv nv ]; +$conf->data->set( iv => 'int', nv => 'float' ); +# Set a value for 'libjit_has_alloca' to avoid uninitialized value warning. +$conf->data->set( 'libjit_has_alloca' => 1 ); +my $ret = $step->runstep($conf); +ok( $ret, "runstep() returned true value" ); +foreach (keys %{$step->{targets}}) { + ok(-f $step->{targets}{$_}, "$_ target generated"); +} + +# re-set for next test +$conf->data->set(%orig_conf); +$step->set_result( '' ); +foreach (keys %{$step->{targets}}) { + if (exists $orig_files{$_}) { + move( $orig_files{$_}, $step->{targets}{$_} ); + } else { + unlink $_; + } +} + +$conf->replenish($serialized); + +pass("Completed all tests in $0"); + +################### DOCUMENTATION ################### + +=head1 NAME + + gen/libjit-01.t - test gen::libjit + +=head1 SYNOPSIS + + % prove t/steps/gen/libjit-01.t + +=head1 DESCRIPTION + +The files in this directory test functionality used by F. + +The tests in this file test gen::libjit. + +=head1 SEE ALSO + +config::gen::libjit, F. + +=cut + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: diff --git a/tools/build/nativecall.pl b/tools/build/nativecall.pl index 9edd1a0..f54d33c 100644 --- a/tools/build/nativecall.pl +++ b/tools/build/nativecall.pl @@ -30,6 +30,9 @@ F. use strict; use warnings; +use lib 'lib'; +use Parrot::NativeCall; + my $opt_warndups = 0; # This file will eventually be compiled @@ -37,64 +40,7 @@ open my $NCI, '>', 'src/nci.c' or die "Can't create nci.c: $!"; print_head( \@ARGV ); - -my %sig_table = ( - p => { - as_proto => "void *", - other_decl => "PMC * const final_destination = pmc_new(interp, enum_class_UnManagedStruct);", - sig_char => "P", - ret_assign => "VTABLE_set_pointer(interp, final_destination, return_data);\n Parrot_pcc_fill_returns_from_c_args(interp, call_object, \"P\", final_destination);", - }, - i => { as_proto => "int", sig_char => "I" }, - l => { as_proto => "long", sig_char => "I" }, - c => { as_proto => "char", sig_char => "I" }, - s => { as_proto => "short", sig_char => "I" }, - f => { as_proto => "float", sig_char => "N" }, - d => { as_proto => "double", sig_char => "N" }, - t => { as_proto => "char *", - other_decl => "STRING *final_destination;", - ret_assign => "final_destination = Parrot_str_new(interp, return_data, 0);\n Parrot_pcc_fill_returns_from_c_args(interp, call_object, \"S\", final_destination);", - sig_char => "S" }, - v => { as_proto => "void", - return_type => "void *", - sig_char => "v", - ret_assign => "", - func_call_assign => "" - }, - P => { as_proto => "PMC *", sig_char => "P" }, - O => { as_proto => "PMC *", returns => "", sig_char => "Pi" }, - J => { as_proto => "PARROT_INTERP", returns => "", sig_char => "" }, - S => { as_proto => "STRING *", sig_char => "S" }, - I => { as_proto => "INTVAL", sig_char => "I" }, - N => { as_proto => "FLOATVAL", sig_char => "N" }, - b => { as_proto => "void *", as_return => "", sig_char => "S" }, - B => { as_proto => "char **", as_return => "", sig_char => "S" }, - # These should be replaced by modifiers in the future - 2 => { as_proto => "short *", sig_char => "P", return_type => "short", - ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, - 3 => { as_proto => "int *", sig_char => "P", return_type => "int", - ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, - 4 => { as_proto => "long *", sig_char => "P", return_type => "long", - ret_assign => 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "I", return_data);' }, - L => { as_proto => "long *", as_return => "" }, - T => { as_proto => "char **", as_return => "" }, - V => { as_proto => "void **", as_return => "", sig_char => "P" }, - '@' => { as_proto => "PMC *", as_return => "", cname => "xAT_", sig_char => 'Ps' }, -); - -for (values %sig_table) { - if (not exists $_->{as_return}) { $_->{as_return} = $_->{as_proto} } - if (not exists $_->{return_type}) { $_->{return_type} = $_->{as_proto} } - if (not exists $_->{return_type_decl}) { $_->{return_type_decl} = $_->{return_type} } - if (not exists $_->{ret_assign} and exists $_->{sig_char}) { - $_->{ret_assign} = 'Parrot_pcc_fill_returns_from_c_args(interp, call_object, "' - . $_->{sig_char} . '", return_data);'; - } - if (not exists $_->{func_call_assign}) { - $_->{func_call_assign} = "return_data = " - } -} - +my %sig_table = %Parrot::NativeCall::signature_table; my $temp_cnt = 0; my (@put_pointer, @put_pointer_nci_too, @nci_defs); @@ -494,17 +440,13 @@ SHIM(PMC *pmc_nci), NOTNULL(STRING *signature), SHIM(int *jitted)) return F2DPTR(VTABLE_get_pointer(interp, b)); } else { - int jit_size; - void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature, &jit_size); + void *priv; + void * const result = Parrot_jit_build_call_func(interp, pmc_nci, signature, &priv); if (result) { - struct jit_buffer_private_data *priv; *jitted = 1; temp_pmc = pmc_new(interp, enum_class_ManagedStruct); VTABLE_set_pointer(interp, temp_pmc, (void *)result); #ifdef PARROT_HAS_EXEC_PROTECT - priv = (struct jit_buffer_private_data *) - mem_sys_allocate(sizeof(struct jit_buffer_private_data)); - priv->size = jit_size; SETATTR_ManagedStruct_custom_free_func(interp, temp_pmc, Parrot_jit_free_buffer); SETATTR_ManagedStruct_custom_free_priv(interp, temp_pmc, priv); SETATTR_ManagedStruct_custom_clone_func(interp, temp_pmc, Parrot_jit_clone_buffer);