From e702b2722850a1070fe05f108d85b02da4d35c22 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 13:44:31 +0200 Subject: [PATCH 01/11] Rework test for invalid callbacks The old test relied on To_Host being called from the constructor. Add a custom test class to invoke an invalid callback from C. --- runtime/core/Clownfish/Test/TestObj.c | 7 +++++++ runtime/core/Clownfish/Test/TestObj.cfh | 10 ++++++++++ runtime/perl/t/binding/019-obj.t | 8 ++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/runtime/core/Clownfish/Test/TestObj.c b/runtime/core/Clownfish/Test/TestObj.c index c0d25eaa..1bac6426 100644 --- a/runtime/core/Clownfish/Test/TestObj.c +++ b/runtime/core/Clownfish/Test/TestObj.c @@ -151,6 +151,13 @@ TestObj_Run_IMP(TestObj *self, TestBatchRunner *runner) { /*********************************************************************/ +void +CallbackTestObj_Invoke_Callback_IMP(CallbackTestObj *self) { + CallbackTestObj_Invalid_Callback(self); +} + +/*********************************************************************/ + String* AliasTestObj_Aliased_IMP(AliasTestObj *self) { UNUSED_VAR(self); diff --git a/runtime/core/Clownfish/Test/TestObj.cfh b/runtime/core/Clownfish/Test/TestObj.cfh index 958224bf..885ad7f2 100644 --- a/runtime/core/Clownfish/Test/TestObj.cfh +++ b/runtime/core/Clownfish/Test/TestObj.cfh @@ -26,6 +26,16 @@ class Clownfish::Test::TestObj Run(TestObj *self, TestBatchRunner *runner); } +class Clownfish::Test::CallbackTestObj { + /** A method that can't be overridden from the host language. + */ + abstract void* + Invalid_Callback(CallbackTestObj *self); + + void + Invoke_Callback(CallbackTestObj *self); +} + class Clownfish::Test::AliasTestObj { incremented String* Aliased(AliasTestObj *self); diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t index 93ad0e87..5de41df7 100644 --- a/runtime/perl/t/binding/019-obj.t +++ b/runtime/perl/t/binding/019-obj.t @@ -46,9 +46,9 @@ use base qw( Clownfish::Obj ); } package InvalidCallbackTestObj; -use base qw( Clownfish::Obj ); +use base qw( Clownfish::Test::CallbackTestObj ); { - sub to_host {} + sub invalid_callback {} } package OverriddenAliasTestObj; @@ -138,8 +138,8 @@ SKIP: { like( $@, qr/NULL/, "Don't allow methods without nullable return values to return NULL" ); - eval { InvalidCallbackTestObj->new; }; - like( $@, qr/Can't override to_host via binding/ ); + eval { InvalidCallbackTestObj->new->invoke_callback; }; + like( $@, qr/Can't override invalid_callback via binding/ ); } my $alias_test = Clownfish::Test::AliasTestObj->new; From 7a4aeb9989c9b15e23cec8298233aac2ba355b22 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 13:49:42 +0200 Subject: [PATCH 02/11] Avoid unwanted calls to To_Host Make sure that Perl constructors and XSBind_cfish_obj_to_sv don't invoke To_Host but always return a reference to a Clownfish::Obj. Don't call To_Host when mortalizing objects converted from Perl arrays and hashes. --- compiler/src/CFCPerlConstructor.c | 2 +- runtime/perl/xs/XSBind.c | 23 +++++++++++++++-------- runtime/perl/xs/XSBind.h | 11 +++++------ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/compiler/src/CFCPerlConstructor.c b/compiler/src/CFCPerlConstructor.c index c1b98393..9dfce1f3 100644 --- a/compiler/src/CFCPerlConstructor.c +++ b/compiler/src/CFCPerlConstructor.c @@ -133,7 +133,7 @@ CFCPerlConstructor_xsub_def(CFCPerlConstructor *self, CFCClass *klass) { "\n" " retval = %s(%s);\n" " if (retval) {\n" - " ST(0) = (SV*)CFISH_Obj_To_Host((cfish_Obj*)retval);\n" + " ST(0) = CFISH_OBJ_TO_SV(retval);\n" " CFISH_DECREF_NN(retval);\n" " }\n" " else {\n" diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index ab2d8ae7..fa571f98 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -130,7 +130,7 @@ XSBind_maybe_sv_to_cfish_obj(pTHX_ SV *sv, cfish_Class *klass, // Mortalize the converted object -- which is somewhat // dangerous, but is the only way to avoid requiring that the // caller take responsibility for a refcount. - SV *mortal = (SV*)CFISH_Obj_To_Host(retval); + SV *mortal = XSBind_cfish_obj_to_sv(aTHX_ retval); CFISH_DECREF(retval); sv_2mortal(mortal); } @@ -757,20 +757,21 @@ cfish_dec_refcount(void *vself) { return modified_refcount; } -void* -CFISH_Obj_To_Host_IMP(cfish_Obj *self) { - dTHX; +SV* +XSBind_cfish_obj_to_sv(pTHX_ cfish_Obj *obj) { + if (obj == NULL) { return newSV(0); } + SV *perl_obj; - if (self->ref.count & XSBIND_REFCOUNT_FLAG) { - perl_obj = S_lazy_init_host_obj(aTHX_ self); + if (obj->ref.count & XSBIND_REFCOUNT_FLAG) { + perl_obj = S_lazy_init_host_obj(aTHX_ obj); } else { - perl_obj = newRV_inc((SV*)self->ref.host_obj); + perl_obj = newRV_inc((SV*)obj->ref.host_obj); } // Enable overloading for Perl 5.8.x #if PERL_VERSION <= 8 - HV *stash = SvSTASH((SV*)self->ref.host_obj); + HV *stash = SvSTASH((SV*)obj->ref.host_obj); if (Gv_AMG(stash)) { SvAMAGIC_on(perl_obj); } @@ -779,6 +780,12 @@ CFISH_Obj_To_Host_IMP(cfish_Obj *self) { return perl_obj; } +void* +CFISH_Obj_To_Host_IMP(cfish_Obj *self) { + dTHX; + return XSBind_cfish_obj_to_sv(aTHX_ self); +} + /*************************** Clownfish::Class ******************************/ cfish_Obj* diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h index 976d3da6..e75b9484 100644 --- a/runtime/perl/xs/XSBind.h +++ b/runtime/perl/xs/XSBind.h @@ -80,15 +80,14 @@ cfish_XSBind_maybe_sv_to_cfish_obj(pTHX_ SV *sv, cfish_Class *klass, /** Derive an SV from a Clownfish object. If the Clownfish object is NULL, the SV - * will be undef. + * will be undef. Doesn't invoke To_Host and always returns a reference to a + * Clownfish::Obj. * * The new SV has single refcount for which the caller must take * responsibility. */ -static CFISH_INLINE SV* -cfish_XSBind_cfish_obj_to_sv(pTHX_ cfish_Obj *obj) { - return obj ? (SV*)CFISH_Obj_To_Host(obj) : newSV(0); -} +CFISH_VISIBLE SV* +cfish_XSBind_cfish_obj_to_sv(pTHX_ cfish_Obj *obj); /** XSBind_cfish_obj_to_sv, with a cast. */ @@ -103,7 +102,7 @@ static CFISH_INLINE SV* cfish_XSBind_cfish_obj_to_sv_noinc(pTHX_ cfish_Obj *obj) { SV *retval; if (obj) { - retval = (SV*)CFISH_Obj_To_Host(obj); + retval = cfish_XSBind_cfish_obj_to_sv(aTHX_ obj); CFISH_DECREF_NN(obj); } else { From 7bceed1d72ab4d0a97426a4003066fe42403344b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 12:56:43 +0200 Subject: [PATCH 03/11] Implement To_Host for Nums --- runtime/core/Clownfish/Num.cfh | 15 ++++++++ runtime/perl/xs/XSBind.c | 67 +++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/runtime/core/Clownfish/Num.cfh b/runtime/core/Clownfish/Num.cfh index b43d958a..781048a7 100644 --- a/runtime/core/Clownfish/Num.cfh +++ b/runtime/core/Clownfish/Num.cfh @@ -87,6 +87,9 @@ final class Clownfish::Float32 inherits Clownfish::FloatNum { inert Float32* new(float value); + void* + To_Host(Float32 *self); + void Set_Value(Float32 *self, float value); @@ -121,6 +124,9 @@ final class Clownfish::Float64 inherits Clownfish::FloatNum { inert Float64* new(double value); + void* + To_Host(Float64 *self); + void Set_Value(Float64 *self, double value); @@ -156,6 +162,9 @@ final class Clownfish::Integer32 nickname Int32 inert Integer32* new(int32_t value); + void* + To_Host(Integer32 *self); + void Set_Value(Integer32 *self, int32_t value); @@ -192,6 +201,9 @@ final class Clownfish::Integer64 nickname Int64 inert Integer64* new(int64_t value); + void* + To_Host(Integer64 *self); + void Set_Value(Integer64 *self, int64_t value); @@ -240,6 +252,9 @@ class Clownfish::BoolNum nickname Bool inherits Clownfish::IntNum { public void Destroy(BoolNum *self); + void* + To_Host(BoolNum *self); + bool Get_Value(BoolNum *self); diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index fa571f98..72c4337e 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -19,6 +19,11 @@ #define C_CFISH_OBJ #define C_CFISH_CLASS +#define C_CFISH_FLOAT32 +#define C_CFISH_FLOAT64 +#define C_CFISH_INTEGER32 +#define C_CFISH_INTEGER64 +#define C_CFISH_BOOLNUM #define NEED_newRV_noinc #include "charmony.h" #include "XSBind.h" @@ -160,27 +165,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (cfish_Obj_is_a(obj, CFISH_HASH)) { return S_cfish_hash_to_perl_hash(aTHX_ (cfish_Hash*)obj); } - else if (cfish_Obj_is_a(obj, CFISH_FLOATNUM)) { - return newSVnv(CFISH_FloatNum_To_F64((cfish_FloatNum*)obj)); - } - else if (obj == (cfish_Obj*)CFISH_TRUE) { - return newSViv(1); - } - else if (obj == (cfish_Obj*)CFISH_FALSE) { - return newSViv(0); - } - else if (sizeof(IV) == 8 && cfish_Obj_is_a(obj, CFISH_INTNUM)) { - int64_t num = CFISH_IntNum_To_I64((cfish_IntNum*)obj); - return newSViv((IV)num); - } - else if (sizeof(IV) == 4 && cfish_Obj_is_a(obj, CFISH_INTEGER32)) { - int32_t num = (int32_t)CFISH_Int32_To_I64((cfish_Integer32*)obj); - return newSViv((IV)num); - } - else if (sizeof(IV) == 4 && cfish_Obj_is_a(obj, CFISH_INTEGER64)) { - int64_t num = CFISH_Int64_To_I64((cfish_Integer64*)obj); - return newSVnv((double)num); // lossy - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -1048,6 +1032,47 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/****************************** Clownfish::Num ******************************/ + +void* +CFISH_Float32_To_Host_IMP(cfish_Float32 *self) { + dTHX; + return newSVnv(self->value); +} + +void* +CFISH_Float64_To_Host_IMP(cfish_Float64 *self) { + dTHX; + return newSVnv(self->value); +} + +void* +CFISH_Int32_To_Host_IMP(cfish_Integer32 *self) { + dTHX; + return newSViv((IV)self->value); +} + +void* +CFISH_Int64_To_Host_IMP(cfish_Integer64 *self) { + dTHX; + SV *sv = NULL; + + if (sizeof(IV) >= 8) { + sv = newSViv((IV)self->value); + } + else { + sv = newSVnv((double)self->value); // lossy + } + + return sv; +} + +void* +CFISH_Bool_To_Host_IMP(cfish_BoolNum *self) { + dTHX; + return newSViv((IV)self->value); +} + /********************* Clownfish::TestHarness::TestUtils ********************/ From dc82fc54c3faf929b271fca886feab9fb02e06da Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 13:53:05 +0200 Subject: [PATCH 04/11] Implement Hash_To_Host --- runtime/core/Clownfish/Hash.cfh | 3 ++ runtime/perl/xs/XSBind.c | 58 +++++++++++++++------------------ 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/runtime/core/Clownfish/Hash.cfh b/runtime/core/Clownfish/Hash.cfh index 62174159..95f47791 100644 --- a/runtime/core/Clownfish/Hash.cfh +++ b/runtime/core/Clownfish/Hash.cfh @@ -44,6 +44,9 @@ public final class Clownfish::Hash inherits Clownfish::Obj { inert String* get_tombstone(); + void* + To_Host(Hash *self); + /** Empty the hash of all key-value pairs. */ public void diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 72c4337e..75d69418 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -54,10 +54,6 @@ S_perl_array_to_cfish_array(pTHX_ AV *parray); static SV* S_cfish_array_to_perl_array(pTHX_ cfish_Vector *varray); -// Convert a Hash to a Perl hash. Caller takes responsibility for a refcount. -static SV* -S_cfish_hash_to_perl_hash(pTHX_ cfish_Hash *hash); - cfish_Obj* XSBind_new_blank_obj(pTHX_ SV *either_sv) { cfish_Class *klass; @@ -162,9 +158,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (cfish_Obj_is_a(obj, CFISH_VECTOR)) { return S_cfish_array_to_perl_array(aTHX_ (cfish_Vector*)obj); } - else if (cfish_Obj_is_a(obj, CFISH_HASH)) { - return S_cfish_hash_to_perl_hash(aTHX_ (cfish_Hash*)obj); - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -334,30 +327,6 @@ S_cfish_array_to_perl_array(pTHX_ cfish_Vector *varray) { return newRV_noinc((SV*)perl_array); } -static SV* -S_cfish_hash_to_perl_hash(pTHX_ cfish_Hash *hash) { - HV *perl_hash = newHV(); - cfish_HashIterator *iter = cfish_HashIter_new(hash); - - // Iterate over key-value pairs. - while (CFISH_HashIter_Next(iter)) { - cfish_String *key = CFISH_HashIter_Get_Key(iter); - const char *key_ptr = CFISH_Str_Get_Ptr8(key); - I32 key_size = CFISH_Str_Get_Size(key); - - // Recurse for each value. - cfish_Obj *val = CFISH_HashIter_Get_Value(iter); - SV *val_sv = XSBind_cfish_to_perl(aTHX_ val); - - // Using a negative `klen` argument to signal UTF-8 is undocumented - // in older Perl versions but works since 5.8.0. - hv_store(perl_hash, key_ptr, -key_size, val_sv, 0); - } - - CFISH_DECREF(iter); - return newRV_noinc((SV*)perl_hash); -} - struct trap_context { SV *routine; SV *context; @@ -1032,6 +1001,33 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/***************************** Clownfish::Hash ******************************/ + +void* +CFISH_Hash_To_Host_IMP(cfish_Hash *self) { + dTHX; + HV *perl_hash = newHV(); + cfish_HashIterator *iter = cfish_HashIter_new(self); + + // Iterate over key-value pairs. + while (CFISH_HashIter_Next(iter)) { + cfish_String *key = CFISH_HashIter_Get_Key(iter); + const char *key_ptr = CFISH_Str_Get_Ptr8(key); + I32 key_size = CFISH_Str_Get_Size(key); + + // Recurse for each value. + cfish_Obj *val = CFISH_HashIter_Get_Value(iter); + SV *val_sv = XSBind_cfish_to_perl(aTHX_ val); + + // Using a negative `klen` argument to signal UTF-8 is undocumented + // in older Perl versions but works since 5.8.0. + hv_store(perl_hash, key_ptr, -key_size, val_sv, 0); + } + + CFISH_DECREF(iter); + return newRV_noinc((SV*)perl_hash); +} + /****************************** Clownfish::Num ******************************/ void* From c7176523871d496d08e17de4d7822783c98426f3 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 13:58:00 +0200 Subject: [PATCH 05/11] Implement Vec_To_Host --- runtime/core/Clownfish/Vector.cfh | 3 ++ runtime/perl/xs/XSBind.c | 59 ++++++++++++++----------------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/runtime/core/Clownfish/Vector.cfh b/runtime/core/Clownfish/Vector.cfh index 4034ebf9..92719883 100644 --- a/runtime/core/Clownfish/Vector.cfh +++ b/runtime/core/Clownfish/Vector.cfh @@ -34,6 +34,9 @@ public final class Clownfish::Vector nickname Vec inherits Clownfish::Obj { public inert Vector* init(Vector *self, size_t capacity = 0); + void* + To_Host(Vector *self); + /** Push an item onto the end of a Vector. */ public void diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 75d69418..0e8a579f 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -49,11 +49,6 @@ S_perl_hash_to_cfish_hash(pTHX_ HV *phash); static cfish_Vector* S_perl_array_to_cfish_array(pTHX_ AV *parray); -// Convert a Vector to a Perl array. Caller takes responsibility for a -// refcount. -static SV* -S_cfish_array_to_perl_array(pTHX_ cfish_Vector *varray); - cfish_Obj* XSBind_new_blank_obj(pTHX_ SV *either_sv) { cfish_Class *klass; @@ -155,9 +150,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (cfish_Obj_is_a(obj, CFISH_BYTEBUF)) { return XSBind_bb_to_sv(aTHX_ (cfish_ByteBuf*)obj); } - else if (cfish_Obj_is_a(obj, CFISH_VECTOR)) { - return S_cfish_array_to_perl_array(aTHX_ (cfish_Vector*)obj); - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -303,30 +295,6 @@ S_perl_array_to_cfish_array(pTHX_ AV *parray) { return retval; } -static SV* -S_cfish_array_to_perl_array(pTHX_ cfish_Vector *varray) { - AV *perl_array = newAV(); - uint32_t num_elems = CFISH_Vec_Get_Size(varray); - - // Iterate over array elems. - if (num_elems) { - av_fill(perl_array, num_elems - 1); - for (uint32_t i = 0; i < num_elems; i++) { - cfish_Obj *val = CFISH_Vec_Fetch(varray, i); - if (val == NULL) { - continue; - } - else { - // Recurse for each value. - SV *const val_sv = XSBind_cfish_to_perl(aTHX_ val); - av_store(perl_array, i, val_sv); - } - } - } - - return newRV_noinc((SV*)perl_array); -} - struct trap_context { SV *routine; SV *context; @@ -1001,6 +969,33 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/**************************** Clownfish::Vector *****************************/ + +void* +CFISH_Vec_To_Host_IMP(cfish_Vector *self) { + dTHX; + AV *perl_array = newAV(); + uint32_t num_elems = CFISH_Vec_Get_Size(self); + + // Iterate over array elems. + if (num_elems) { + av_fill(perl_array, num_elems - 1); + for (uint32_t i = 0; i < num_elems; i++) { + cfish_Obj *val = CFISH_Vec_Fetch(self, i); + if (val == NULL) { + continue; + } + else { + // Recurse for each value. + SV *const val_sv = XSBind_cfish_to_perl(aTHX_ val); + av_store(perl_array, i, val_sv); + } + } + } + + return newRV_noinc((SV*)perl_array); +} + /***************************** Clownfish::Hash ******************************/ void* From eadeae084ace20abe0d5ef7d6b01d44e04567dcd Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 14:10:18 +0200 Subject: [PATCH 06/11] Implement BB_To_Host --- runtime/core/Clownfish/ByteBuf.cfh | 3 +++ runtime/perl/xs/XSBind.c | 18 ++++++++---------- runtime/perl/xs/XSBind.h | 6 ------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/runtime/core/Clownfish/ByteBuf.cfh b/runtime/core/Clownfish/ByteBuf.cfh index 93e5a7c1..43d67102 100644 --- a/runtime/core/Clownfish/ByteBuf.cfh +++ b/runtime/core/Clownfish/ByteBuf.cfh @@ -59,6 +59,9 @@ final class Clownfish::ByteBuf nickname BB inherits Clownfish::Obj { inert int compare(const void *va, const void *vb); + void* + To_Host(ByteBuf *self); + /** Set the object's size member. If greater than the object's capacity, * throws an error. */ diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 0e8a579f..31d600d8 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -147,9 +147,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (cfish_Obj_is_a(obj, CFISH_BLOB)) { return XSBind_blob_to_sv(aTHX_ (cfish_Blob*)obj); } - else if (cfish_Obj_is_a(obj, CFISH_BYTEBUF)) { - return XSBind_bb_to_sv(aTHX_ (cfish_ByteBuf*)obj); - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -216,13 +213,6 @@ XSBind_blob_to_sv(pTHX_ cfish_Blob *blob) { : newSV(0); } -SV* -XSBind_bb_to_sv(pTHX_ cfish_ByteBuf *bb) { - return bb - ? newSVpvn(CFISH_BB_Get_Buf(bb), CFISH_BB_Get_Size(bb)) - : newSV(0); -} - SV* XSBind_str_to_sv(pTHX_ cfish_String *str) { if (!str) { @@ -969,6 +959,14 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/**************************** Clownfish::ByteBuf ****************************/ + +void* +CFISH_BB_To_Host_IMP(cfish_ByteBuf *self) { + dTHX; + return newSVpvn(CFISH_BB_Get_Buf(self), CFISH_BB_Get_Size(self)); +} + /**************************** Clownfish::Vector *****************************/ void* diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h index e75b9484..0a300f39 100644 --- a/runtime/perl/xs/XSBind.h +++ b/runtime/perl/xs/XSBind.h @@ -136,11 +136,6 @@ cfish_XSBind_perl_to_cfish(pTHX_ SV *sv); CFISH_VISIBLE SV* cfish_XSBind_blob_to_sv(pTHX_ cfish_Blob *blob); -/** Convert a ByteBuf into a new string SV. - */ -CFISH_VISIBLE SV* -cfish_XSBind_bb_to_sv(pTHX_ cfish_ByteBuf *bb); - /** Convert a String into a new UTF-8 string SV. */ CFISH_VISIBLE SV* @@ -319,7 +314,6 @@ cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start, #define XSBind_cfish_to_perl cfish_XSBind_cfish_to_perl #define XSBind_perl_to_cfish cfish_XSBind_perl_to_cfish #define XSBind_blob_to_sv cfish_XSBind_blob_to_sv -#define XSBind_bb_to_sv cfish_XSBind_bb_to_sv #define XSBind_str_to_sv cfish_XSBind_str_to_sv #define XSBind_trap cfish_XSBind_trap #define XSBind_allot_params cfish_XSBind_allot_params From 40d863c7e1bcaf1db0b08d8c88ab7ba50c4dde7b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 14:26:13 +0200 Subject: [PATCH 07/11] Implement Blob_To_Host --- runtime/core/Clownfish/Blob.cfh | 3 +++ runtime/perl/xs/XSBind.c | 18 ++++++++---------- runtime/perl/xs/XSBind.h | 6 ------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/runtime/core/Clownfish/Blob.cfh b/runtime/core/Clownfish/Blob.cfh index 4f236e02..2ad7a4a6 100644 --- a/runtime/core/Clownfish/Blob.cfh +++ b/runtime/core/Clownfish/Blob.cfh @@ -50,6 +50,9 @@ final class Clownfish::Blob inherits Clownfish::Obj { inert int compare(const void *va, const void *vb); + void* + To_Host(Blob *self); + /** Accessor for "size" member. */ public size_t diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 31d600d8..f1a9c21e 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -144,9 +144,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { else if (cfish_Obj_is_a(obj, CFISH_STRING)) { return XSBind_str_to_sv(aTHX_ (cfish_String*)obj); } - else if (cfish_Obj_is_a(obj, CFISH_BLOB)) { - return XSBind_blob_to_sv(aTHX_ (cfish_Blob*)obj); - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -206,13 +203,6 @@ XSBind_perl_to_cfish(pTHX_ SV *sv) { return retval; } -SV* -XSBind_blob_to_sv(pTHX_ cfish_Blob *blob) { - return blob - ? newSVpvn(CFISH_Blob_Get_Buf(blob), CFISH_Blob_Get_Size(blob)) - : newSV(0); -} - SV* XSBind_str_to_sv(pTHX_ cfish_String *str) { if (!str) { @@ -959,6 +949,14 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/***************************** Clownfish::Blob ******************************/ + +void* +CFISH_Blob_To_Host_IMP(cfish_Blob *self) { + dTHX; + return newSVpvn(CFISH_Blob_Get_Buf(self), CFISH_Blob_Get_Size(self)); +} + /**************************** Clownfish::ByteBuf ****************************/ void* diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h index 0a300f39..711adab3 100644 --- a/runtime/perl/xs/XSBind.h +++ b/runtime/perl/xs/XSBind.h @@ -131,11 +131,6 @@ cfish_XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj); CFISH_VISIBLE cfish_Obj* cfish_XSBind_perl_to_cfish(pTHX_ SV *sv); -/** Convert a Blob into a new string SV. - */ -CFISH_VISIBLE SV* -cfish_XSBind_blob_to_sv(pTHX_ cfish_Blob *blob); - /** Convert a String into a new UTF-8 string SV. */ CFISH_VISIBLE SV* @@ -313,7 +308,6 @@ cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start, #define XSBind_cfish_obj_to_sv_noinc cfish_XSBind_cfish_obj_to_sv_noinc #define XSBind_cfish_to_perl cfish_XSBind_cfish_to_perl #define XSBind_perl_to_cfish cfish_XSBind_perl_to_cfish -#define XSBind_blob_to_sv cfish_XSBind_blob_to_sv #define XSBind_str_to_sv cfish_XSBind_str_to_sv #define XSBind_trap cfish_XSBind_trap #define XSBind_allot_params cfish_XSBind_allot_params From 4afe9a6bcc3c8a0c74c7a042bea582d5db80fe58 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 14:43:16 +0200 Subject: [PATCH 08/11] Implement Str_To_Host --- compiler/src/CFCPerlMethod.c | 9 ++---- runtime/core/Clownfish/String.cfh | 3 ++ .../perl/buildlib/Clownfish/Build/Binding.pm | 9 +----- runtime/perl/xs/XSBind.c | 31 ++++++++----------- runtime/perl/xs/XSBind.h | 6 ---- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/compiler/src/CFCPerlMethod.c b/compiler/src/CFCPerlMethod.c index ca5f34e1..afe34c03 100644 --- a/compiler/src/CFCPerlMethod.c +++ b/compiler/src/CFCPerlMethod.c @@ -500,13 +500,8 @@ S_callback_start(CFCMethod *method) { num_buf, ");\n", NULL); } - if (CFCType_is_string_type(type)) { - // Convert Clownfish string type to UTF-8 Perl string scalars. - params = CFCUtil_cat(params, " mPUSHs(XSBind_str_to_sv(", - "aTHX_ (cfish_String*)", name, "));\n", NULL); - } - else if (CFCType_is_object(type)) { - // Wrap other Clownfish object types in Perl objects. + if (CFCType_is_object(type)) { + // Wrap Clownfish object types in Perl objects. params = CFCUtil_cat(params, " mPUSHs(XSBind_cfish_to_perl(", "aTHX_ (cfish_Obj*)", name, "));\n", NULL); } diff --git a/runtime/core/Clownfish/String.cfh b/runtime/core/Clownfish/String.cfh index 17418b93..932f36b9 100644 --- a/runtime/core/Clownfish/String.cfh +++ b/runtime/core/Clownfish/String.cfh @@ -120,6 +120,9 @@ final class Clownfish::String nickname Str inert bool less_than(const void *va, const void *vb); + void* + To_Host(String *self); + /** Return the concatenation of the String and `other`. */ incremented String* diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm b/runtime/perl/buildlib/Clownfish/Build/Binding.pm index 8097d6bf..309f7e83 100644 --- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm +++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm @@ -226,13 +226,6 @@ _clone(self) CODE: RETVAL = CFISH_OBJ_TO_SV_NOINC(CFISH_Str_Clone_IMP(self)); OUTPUT: RETVAL - -SV* -to_perl(self) - cfish_String *self; -CODE: - RETVAL = XSBind_str_to_sv(aTHX_ self); -OUTPUT: RETVAL END_XS_CODE my $binding = Clownfish::CFC::Binding::Perl::Class->new( @@ -496,7 +489,7 @@ get_class_name(self) cfish_Obj *self CODE: cfish_String *class_name = cfish_Obj_get_class_name(self); - RETVAL = cfish_XSBind_str_to_sv(aTHX_ class_name); + RETVAL = (SV*)CFISH_Str_To_Host(class_name); OUTPUT: RETVAL bool diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index f1a9c21e..630febf1 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -141,9 +141,6 @@ XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { if (obj == NULL) { return newSV(0); } - else if (cfish_Obj_is_a(obj, CFISH_STRING)) { - return XSBind_str_to_sv(aTHX_ (cfish_String*)obj); - } else { return (SV*)CFISH_Obj_To_Host(obj); } @@ -203,18 +200,6 @@ XSBind_perl_to_cfish(pTHX_ SV *sv) { return retval; } -SV* -XSBind_str_to_sv(pTHX_ cfish_String *str) { - if (!str) { - return newSV(0); - } - else { - SV *sv = newSVpvn(CFISH_Str_Get_Ptr8(str), CFISH_Str_Get_Size(str)); - SvUTF8_on(sv); - return sv; - } -} - static cfish_Hash* S_perl_hash_to_cfish_hash(pTHX_ HV *phash) { uint32_t num_keys = hv_iterinit(phash); @@ -743,7 +728,7 @@ cfish_Class_fresh_host_methods(cfish_String *class_name) { SAVETMPS; EXTEND(SP, 1); PUSHMARK(SP); - mPUSHs(XSBind_str_to_sv(aTHX_ class_name)); + mPUSHs((SV*)CFISH_Str_To_Host(class_name)); PUTBACK; call_pv("Clownfish::Class::_fresh_host_methods", G_SCALAR); SPAGAIN; @@ -762,7 +747,7 @@ cfish_Class_find_parent_class(cfish_String *class_name) { SAVETMPS; EXTEND(SP, 1); PUSHMARK(SP); - mPUSHs(XSBind_str_to_sv(aTHX_ class_name)); + mPUSHs((SV*)CFISH_Str_To_Host(class_name)); PUTBACK; call_pv("Clownfish::Class::_find_parent_class", G_SCALAR); SPAGAIN; @@ -897,7 +882,7 @@ cfish_Err_throw_mess(cfish_Class *klass, cfish_String *message) { void cfish_Err_warn_mess(cfish_String *message) { dTHX; - SV *error_sv = XSBind_str_to_sv(aTHX_ message); + SV *error_sv = (SV*)CFISH_Str_To_Host(message); CFISH_DECREF(message); warn("%s", SvPV_nolen(error_sv)); SvREFCNT_dec(error_sv); @@ -949,6 +934,16 @@ cfish_Err_trap(CFISH_Err_Attempt_t routine, void *context) { return error; } +/**************************** Clownfish::String *****************************/ + +void* +CFISH_Str_To_Host_IMP(cfish_String *self) { + dTHX; + SV *sv = newSVpvn(CFISH_Str_Get_Ptr8(self), CFISH_Str_Get_Size(self)); + SvUTF8_on(sv); + return sv; +} + /***************************** Clownfish::Blob ******************************/ void* diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h index 711adab3..f895854e 100644 --- a/runtime/perl/xs/XSBind.h +++ b/runtime/perl/xs/XSBind.h @@ -131,11 +131,6 @@ cfish_XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj); CFISH_VISIBLE cfish_Obj* cfish_XSBind_perl_to_cfish(pTHX_ SV *sv); -/** Convert a String into a new UTF-8 string SV. - */ -CFISH_VISIBLE SV* -cfish_XSBind_str_to_sv(pTHX_ cfish_String *str); - /** Perl-specific wrapper for Err#trap. The "routine" must be either a * subroutine reference or the name of a subroutine. */ @@ -308,7 +303,6 @@ cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start, #define XSBind_cfish_obj_to_sv_noinc cfish_XSBind_cfish_obj_to_sv_noinc #define XSBind_cfish_to_perl cfish_XSBind_cfish_to_perl #define XSBind_perl_to_cfish cfish_XSBind_perl_to_cfish -#define XSBind_str_to_sv cfish_XSBind_str_to_sv #define XSBind_trap cfish_XSBind_trap #define XSBind_allot_params cfish_XSBind_allot_params #define ALLOT_I8 XSBIND_ALLOT_I8 From e5435615d8f8a0132608fd9d90935b62a4f2f995 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 14:59:43 +0200 Subject: [PATCH 09/11] Make XSBind_cfish_to_perl inline Now XSBind_cfish_to_perl is nothing more than a null-safe wrapper around Obj_To_Host. --- compiler/src/CFCPerlTypeMap.c | 6 ++---- runtime/perl/xs/XSBind.c | 12 +----------- runtime/perl/xs/XSBind.h | 11 +++++------ 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/compiler/src/CFCPerlTypeMap.c b/compiler/src/CFCPerlTypeMap.c index a07928ca..795fddee 100644 --- a/compiler/src/CFCPerlTypeMap.c +++ b/compiler/src/CFCPerlTypeMap.c @@ -121,10 +121,8 @@ CFCPerlTypeMap_to_perl(CFCType *type, const char *cf_var) { char *result = NULL; if (CFCType_is_object(type)) { - const char pattern[] = - "(%s == NULL ?" - " newSV(0) : XSBind_cfish_to_perl(aTHX_ (cfish_Obj*)%s))"; - result = CFCUtil_sprintf(pattern, cf_var, cf_var); + const char pattern[] = "XSBind_cfish_to_perl(aTHX_ (cfish_Obj*)%s)"; + result = CFCUtil_sprintf(pattern, cf_var); } else if (CFCType_is_primitive(type)) { // Convert from a primitive type to a Perl scalar. diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 630febf1..20cd377a 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -136,16 +136,6 @@ XSBind_maybe_sv_to_cfish_obj(pTHX_ SV *sv, cfish_Class *klass, return retval; } -SV* -XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { - if (obj == NULL) { - return newSV(0); - } - else { - return (SV*)CFISH_Obj_To_Host(obj); - } -} - cfish_Obj* XSBind_perl_to_cfish(pTHX_ SV *sv) { cfish_Obj *retval = NULL; @@ -978,7 +968,7 @@ CFISH_Vec_To_Host_IMP(cfish_Vector *self) { } else { // Recurse for each value. - SV *const val_sv = XSBind_cfish_to_perl(aTHX_ val); + SV *const val_sv = (SV*)CFISH_Obj_To_Host(val); av_store(perl_array, i, val_sv); } } diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h index f895854e..465574d2 100644 --- a/runtime/perl/xs/XSBind.h +++ b/runtime/perl/xs/XSBind.h @@ -116,13 +116,12 @@ cfish_XSBind_cfish_obj_to_sv_noinc(pTHX_ cfish_Obj *obj) { #define CFISH_OBJ_TO_SV_NOINC(_obj) \ cfish_XSBind_cfish_obj_to_sv_noinc(aTHX_ (cfish_Obj*)_obj) -/** Deep conversion of Clownfish objects to Perl objects -- Strings to UTF-8 - * SVs, Blobs to SVs, ByteBufs to SVs, Vectors to Perl array refs, Hashes to - * Perl hashrefs, and any other object to a Perl object wrapping the Clownfish - * Obj. +/** Null-safe invocation of Obj_To_Host. */ -CFISH_VISIBLE SV* -cfish_XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj); +static CFISH_INLINE SV* +cfish_XSBind_cfish_to_perl(pTHX_ cfish_Obj *obj) { + return obj ? (SV*)CFISH_Obj_To_Host(obj) : newSV(0); +} /** Deep conversion of Perl data structures to Clownfish objects -- Perl hash * to Hash, Perl array to Vector, Clownfish objects stripped of their From d448dd7f44d53d7ca960a7d2312a644de1b87093 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 18:10:32 +0200 Subject: [PATCH 10/11] Implement To_Host methods for C bindings --- runtime/c/src/Clownfish/Obj.c | 74 +++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/runtime/c/src/Clownfish/Obj.c b/runtime/c/src/Clownfish/Obj.c index 4b753cb9..a037ff11 100644 --- a/runtime/c/src/Clownfish/Obj.c +++ b/runtime/c/src/Clownfish/Obj.c @@ -22,8 +22,13 @@ #include "Clownfish/Obj.h" #include "Clownfish/Class.h" +#include "Clownfish/Blob.h" +#include "Clownfish/ByteBuf.h" #include "Clownfish/Err.h" +#include "Clownfish/Hash.h" +#include "Clownfish/Num.h" #include "Clownfish/String.h" +#include "Clownfish/Vector.h" static CFISH_INLINE bool SI_immortal(cfish_Class *klass) { @@ -108,4 +113,73 @@ Obj_To_Host_IMP(Obj *self) { UNREACHABLE_RETURN(void*); } +void* +Str_To_Host_IMP(String *self) { + Str_To_Host_t super_to_host + = SUPER_METHOD_PTR(STRING, CFISH_Str_To_Host); + return super_to_host(self); +} + +void* +Blob_To_Host_IMP(Blob *self) { + Blob_To_Host_t super_to_host + = SUPER_METHOD_PTR(BLOB, CFISH_Blob_To_Host); + return super_to_host(self); +} + +void* +BB_To_Host_IMP(ByteBuf *self) { + BB_To_Host_t super_to_host + = SUPER_METHOD_PTR(BYTEBUF, CFISH_BB_To_Host); + return super_to_host(self); +} + +void* +Vec_To_Host_IMP(Vector *self) { + Vec_To_Host_t super_to_host + = SUPER_METHOD_PTR(VECTOR, CFISH_Vec_To_Host); + return super_to_host(self); +} + +void* +Hash_To_Host_IMP(Hash *self) { + Hash_To_Host_t super_to_host + = SUPER_METHOD_PTR(HASH, CFISH_Hash_To_Host); + return super_to_host(self); +} + +void* +Float32_To_Host_IMP(Float32 *self) { + Float32_To_Host_t super_to_host + = SUPER_METHOD_PTR(FLOAT32, CFISH_Float32_To_Host); + return super_to_host(self); +} + +void* +Float64_To_Host_IMP(Float64 *self) { + Float64_To_Host_t super_to_host + = SUPER_METHOD_PTR(FLOAT64, CFISH_Float64_To_Host); + return super_to_host(self); +} + +void* +Int32_To_Host_IMP(Integer32 *self) { + Int32_To_Host_t super_to_host + = SUPER_METHOD_PTR(INTEGER32, CFISH_Int32_To_Host); + return super_to_host(self); +} + +void* +Int64_To_Host_IMP(Integer64 *self) { + Int64_To_Host_t super_to_host + = SUPER_METHOD_PTR(INTEGER64, CFISH_Int64_To_Host); + return super_to_host(self); +} + +void* +Bool_To_Host_IMP(BoolNum *self) { + Bool_To_Host_t super_to_host + = SUPER_METHOD_PTR(BOOLNUM, CFISH_Bool_To_Host); + return super_to_host(self); +} From 04e73fac39f178d125c99b5079b1fbf7fb491629 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Fri, 29 May 2015 18:49:24 +0200 Subject: [PATCH 11/11] Implement To_Host methods for Go bindings --- runtime/go/ext/clownfish.c | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/runtime/go/ext/clownfish.c b/runtime/go/ext/clownfish.c index dc88deeb..affe7724 100644 --- a/runtime/go/ext/clownfish.c +++ b/runtime/go/ext/clownfish.c @@ -239,3 +239,76 @@ Err_trap(Err_Attempt_t routine, void *context) { return GoCfish_TrapErr(routine, context); } +/***************************** To_Host methods *****************************/ + +void* +Str_To_Host_IMP(String *self) { + Str_To_Host_t super_to_host + = SUPER_METHOD_PTR(STRING, CFISH_Str_To_Host); + return super_to_host(self); +} + +void* +Blob_To_Host_IMP(Blob *self) { + Blob_To_Host_t super_to_host + = SUPER_METHOD_PTR(BLOB, CFISH_Blob_To_Host); + return super_to_host(self); +} + +void* +BB_To_Host_IMP(ByteBuf *self) { + BB_To_Host_t super_to_host + = SUPER_METHOD_PTR(BYTEBUF, CFISH_BB_To_Host); + return super_to_host(self); +} + +void* +Vec_To_Host_IMP(Vector *self) { + Vec_To_Host_t super_to_host + = SUPER_METHOD_PTR(VECTOR, CFISH_Vec_To_Host); + return super_to_host(self); +} + +void* +Hash_To_Host_IMP(Hash *self) { + Hash_To_Host_t super_to_host + = SUPER_METHOD_PTR(HASH, CFISH_Hash_To_Host); + return super_to_host(self); +} + +void* +Float32_To_Host_IMP(Float32 *self) { + Float32_To_Host_t super_to_host + = SUPER_METHOD_PTR(FLOAT32, CFISH_Float32_To_Host); + return super_to_host(self); +} + +void* +Float64_To_Host_IMP(Float64 *self) { + Float64_To_Host_t super_to_host + = SUPER_METHOD_PTR(FLOAT64, CFISH_Float64_To_Host); + return super_to_host(self); +} + +void* +Int32_To_Host_IMP(Integer32 *self) { + Int32_To_Host_t super_to_host + = SUPER_METHOD_PTR(INTEGER32, CFISH_Int32_To_Host); + return super_to_host(self); +} + +void* +Int64_To_Host_IMP(Integer64 *self) { + Int64_To_Host_t super_to_host + = SUPER_METHOD_PTR(INTEGER64, CFISH_Int64_To_Host); + return super_to_host(self); +} + +void* +Bool_To_Host_IMP(BoolNum *self) { + Bool_To_Host_t super_to_host + = SUPER_METHOD_PTR(BOOLNUM, CFISH_Bool_To_Host); + return super_to_host(self); +} + +