Consolidate XS code. Consolidate all XS code related to the Clownfish core runtime into XSBind.c.
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/f6a05ea6 Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/f6a05ea6 Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/f6a05ea6 Branch: refs/heads/kill_clownfish_host Commit: f6a05ea61c1dc67685755963f81aee82a1e43a01 Parents: 413bf56 Author: Marvin Humphrey <[email protected]> Authored: Wed Nov 14 16:19:12 2012 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Wed Nov 14 16:19:12 2012 -0800 ---------------------------------------------------------------------- perl/xs/Clownfish/Err.c | 146 --------------- perl/xs/Clownfish/LockFreeRegistry.c | 36 ---- perl/xs/Clownfish/Obj.c | 113 ------------ perl/xs/Clownfish/VTable.c | 70 ------- perl/xs/XSBind.c | 285 +++++++++++++++++++++++++++++ 5 files changed, 285 insertions(+), 365 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy/blob/f6a05ea6/perl/xs/Clownfish/Err.c ---------------------------------------------------------------------- diff --git a/perl/xs/Clownfish/Err.c b/perl/xs/Clownfish/Err.c deleted file mode 100644 index 763178d..0000000 --- a/perl/xs/Clownfish/Err.c +++ /dev/null @@ -1,146 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "XSBind.h" -#include "Clownfish/Host.h" - -// Anonymous XSUB helper for Err#trap(). It wraps the supplied C function -// so that it can be run inside a Perl eval block. -static SV *attempt_xsub = NULL; - -XS(lucy_Err_attempt_via_xs) { - dXSARGS; - CHY_UNUSED_VAR(cv); - SP -= items; - if (items != 2) { - CFISH_THROW(CFISH_ERR, "Usage: $sub->(routine, context)"); - }; - IV routine_iv = SvIV(ST(0)); - IV context_iv = SvIV(ST(1)); - Cfish_Err_Attempt_t routine = INT2PTR(Cfish_Err_Attempt_t, routine_iv); - void *context = INT2PTR(void*, context_iv); - routine(context); - XSRETURN(0); -} - -void -lucy_Err_init_class(void) { - char *file = (char*)__FILE__; - attempt_xsub = (SV*)newXS(NULL, lucy_Err_attempt_via_xs, file); -} - -lucy_Err* -lucy_Err_get_error() { - lucy_Err *error - = (lucy_Err*)lucy_Host_callback_obj(LUCY_ERR, "get_error", 0); - CFISH_DECREF(error); // Cancel out incref from callback. - return error; -} - -void -lucy_Err_set_error(lucy_Err *error) { - lucy_Host_callback(LUCY_ERR, "set_error", 1, - CFISH_ARG_OBJ("error", error)); - CFISH_DECREF(error); -} - -void -lucy_Err_do_throw(lucy_Err *err) { - dSP; - SV *error_sv = (SV*)Lucy_Err_To_Host(err); - CFISH_DECREF(err); - ENTER; - SAVETMPS; - PUSHMARK(SP); - XPUSHs(sv_2mortal(error_sv)); - PUTBACK; - call_pv("Clownfish::Err::do_throw", G_DISCARD); - FREETMPS; - LEAVE; -} - -void* -lucy_Err_to_host(lucy_Err *self) { - Lucy_Err_To_Host_t super_to_host - = CFISH_SUPER_METHOD_PTR(LUCY_ERR, Lucy_Err_To_Host); - SV *perl_obj = (SV*)super_to_host(self); - XSBind_enable_overload(perl_obj); - return perl_obj; -} - -void -lucy_Err_throw_mess(lucy_VTable *vtable, lucy_CharBuf *message) { - Lucy_Err_Make_t make - = CFISH_METHOD_PTR(CFISH_CERTIFY(vtable, LUCY_VTABLE), Lucy_Err_Make); - lucy_Err *err = (lucy_Err*)CFISH_CERTIFY(make(NULL), LUCY_ERR); - Lucy_Err_Cat_Mess(err, message); - CFISH_DECREF(message); - lucy_Err_do_throw(err); -} - -void -lucy_Err_warn_mess(lucy_CharBuf *message) { - SV *error_sv = XSBind_cb_to_sv(message); - CFISH_DECREF(message); - warn("%s", SvPV_nolen(error_sv)); - SvREFCNT_dec(error_sv); -} - -lucy_Err* -lucy_Err_trap(Cfish_Err_Attempt_t routine, void *context) { - lucy_Err *error = NULL; - SV *routine_sv = newSViv(PTR2IV(routine)); - SV *context_sv = newSViv(PTR2IV(context)); - dSP; - ENTER; - SAVETMPS; - PUSHMARK(SP); - EXTEND(SP, 2); - PUSHs(sv_2mortal(routine_sv)); - PUSHs(sv_2mortal(context_sv)); - PUTBACK; - - int count = call_sv(attempt_xsub, G_EVAL | G_DISCARD); - if (count != 0) { - lucy_CharBuf *mess - = lucy_CB_newf("'attempt' returned too many values: %i32", - (int32_t)count); - error = lucy_Err_new(mess); - } - else { - SV *dollar_at = get_sv("@", FALSE); - if (SvTRUE(dollar_at)) { - if (sv_isobject(dollar_at) - && sv_derived_from(dollar_at,"Clownfish::Err") - ) { - IV error_iv = SvIV(SvRV(dollar_at)); - error = INT2PTR(lucy_Err*, error_iv); - CFISH_INCREF(error); - } - else { - STRLEN len; - char *ptr = SvPVutf8(dollar_at, len); - lucy_CharBuf *mess = lucy_CB_new_from_trusted_utf8(ptr, len); - error = lucy_Err_new(mess); - } - } - } - FREETMPS; - LEAVE; - - return error; -} - http://git-wip-us.apache.org/repos/asf/lucy/blob/f6a05ea6/perl/xs/Clownfish/LockFreeRegistry.c ---------------------------------------------------------------------- diff --git a/perl/xs/Clownfish/LockFreeRegistry.c b/perl/xs/Clownfish/LockFreeRegistry.c deleted file mode 100644 index 41f7899..0000000 --- a/perl/xs/Clownfish/LockFreeRegistry.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define C_LUCY_OBJ -#define C_LUCY_LOCKFREEREGISTRY -#include "XSBind.h" - -#include "Clownfish/LockFreeRegistry.h" -#include "Clownfish/Host.h" - -void* -lucy_LFReg_to_host(lucy_LockFreeRegistry *self) { - chy_bool_t first_time = self->ref.count < 4 ? true : false; - Lucy_LFReg_To_Host_t to_host - = CFISH_SUPER_METHOD_PTR(LUCY_LOCKFREEREGISTRY, Lucy_LFReg_To_Host); - SV *host_obj = (SV*)to_host(self); - if (first_time) { - SvSHARE((SV*)self->ref.host_obj); - } - return host_obj; -} - - http://git-wip-us.apache.org/repos/asf/lucy/blob/f6a05ea6/perl/xs/Clownfish/Obj.c ---------------------------------------------------------------------- diff --git a/perl/xs/Clownfish/Obj.c b/perl/xs/Clownfish/Obj.c deleted file mode 100644 index 38fcd2d..0000000 --- a/perl/xs/Clownfish/Obj.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define C_LUCY_OBJ - -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" -#include "ppport.h" - -#include "Clownfish/Obj.h" -#include "Clownfish/CharBuf.h" -#include "Clownfish/Err.h" -#include "Clownfish/VTable.h" -#include "Clownfish/Util/Memory.h" - -static void -S_lazy_init_host_obj(lucy_Obj *self) { - SV *inner_obj = newSV(0); - SvOBJECT_on(inner_obj); - PL_sv_objcount++; - SvUPGRADE(inner_obj, SVt_PVMG); - sv_setiv(inner_obj, PTR2IV(self)); - - // Connect class association. - lucy_CharBuf *class_name = Lucy_VTable_Get_Name(self->vtable); - HV *stash = gv_stashpvn((char*)Lucy_CB_Get_Ptr8(class_name), - Lucy_CB_Get_Size(class_name), TRUE); - SvSTASH_set(inner_obj, (HV*)SvREFCNT_inc(stash)); - - /* Up till now we've been keeping track of the refcount in - * self->ref.count. We're replacing ref.count with ref.host_obj, which - * will assume responsibility for maintaining the refcount. ref.host_obj - * starts off with a refcount of 1, so we need to transfer any refcounts - * in excess of that. */ - size_t old_refcount = self->ref.count; - self->ref.host_obj = inner_obj; - while (old_refcount > 1) { - SvREFCNT_inc_simple_void_NN(inner_obj); - old_refcount--; - } -} - -uint32_t -lucy_Obj_get_refcount(lucy_Obj *self) { - return self->ref.count < 4 - ? self->ref.count - : SvREFCNT((SV*)self->ref.host_obj); -} - -lucy_Obj* -lucy_Obj_inc_refcount(lucy_Obj *self) { - switch (self->ref.count) { - case 0: - CFISH_THROW(LUCY_ERR, "Illegal refcount of 0"); - break; // useless - case 1: - case 2: - self->ref.count++; - break; - case 3: - S_lazy_init_host_obj(self); - // fall through - default: - SvREFCNT_inc_simple_void_NN((SV*)self->ref.host_obj); - } - return self; -} - -uint32_t -lucy_Obj_dec_refcount(lucy_Obj *self) { - uint32_t modified_refcount = I32_MAX; - switch (self->ref.count) { - case 0: - CFISH_THROW(LUCY_ERR, "Illegal refcount of 0"); - break; // useless - case 1: - modified_refcount = 0; - Lucy_Obj_Destroy(self); - break; - case 2: - case 3: - modified_refcount = --self->ref.count; - break; - default: - modified_refcount = SvREFCNT((SV*)self->ref.host_obj) - 1; - // If the SV's refcount falls to 0, DESTROY will be invoked from - // Perl-space. - SvREFCNT_dec((SV*)self->ref.host_obj); - } - return modified_refcount; -} - -void* -lucy_Obj_to_host(lucy_Obj *self) { - if (self->ref.count < 4) { S_lazy_init_host_obj(self); } - return newRV_inc((SV*)self->ref.host_obj); -} - - http://git-wip-us.apache.org/repos/asf/lucy/blob/f6a05ea6/perl/xs/Clownfish/VTable.c ---------------------------------------------------------------------- diff --git a/perl/xs/Clownfish/VTable.c b/perl/xs/Clownfish/VTable.c deleted file mode 100644 index 5287924..0000000 --- a/perl/xs/Clownfish/VTable.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define C_LUCY_OBJ -#define C_LUCY_VTABLE -#include "XSBind.h" - -#include "Clownfish/VTable.h" -#include "Clownfish/Host.h" -#include "Clownfish/Util/Memory.h" - -lucy_Obj* -lucy_VTable_foster_obj(lucy_VTable *self, void *host_obj) { - lucy_Obj *obj - = (lucy_Obj*)lucy_Memory_wrapped_calloc(self->obj_alloc_size, 1); - SV *inner_obj = SvRV((SV*)host_obj); - obj->vtable = self; - sv_setiv(inner_obj, PTR2IV(obj)); - obj->ref.host_obj = inner_obj; - return obj; -} - -void -lucy_VTable_register_with_host(lucy_VTable *singleton, lucy_VTable *parent) { - // Register class with host. - lucy_Host_callback(LUCY_VTABLE, "_register", 2, - CFISH_ARG_OBJ("singleton", singleton), - CFISH_ARG_OBJ("parent", parent)); -} - -lucy_VArray* -lucy_VTable_fresh_host_methods(const lucy_CharBuf *class_name) { - return (lucy_VArray*)lucy_Host_callback_obj( - LUCY_VTABLE, - "fresh_host_methods", 1, - CFISH_ARG_STR("class_name", class_name)); -} - -lucy_CharBuf* -lucy_VTable_find_parent_class(const lucy_CharBuf *class_name) { - return lucy_Host_callback_str(LUCY_VTABLE, "find_parent_class", 1, - CFISH_ARG_STR("class_name", class_name)); -} - -void* -lucy_VTable_to_host(lucy_VTable *self) { - chy_bool_t first_time = self->ref.count < 4 ? true : false; - Lucy_VTable_To_Host_t to_host - = CFISH_SUPER_METHOD_PTR(LUCY_VTABLE, Lucy_VTable_To_Host); - SV *host_obj = (SV*)to_host(self); - if (first_time) { - SvSHARE((SV*)self->ref.host_obj); - } - return host_obj; -} - - http://git-wip-us.apache.org/repos/asf/lucy/blob/f6a05ea6/perl/xs/XSBind.c ---------------------------------------------------------------------- diff --git a/perl/xs/XSBind.c b/perl/xs/XSBind.c index ee28681..c210f01 100644 --- a/perl/xs/XSBind.c +++ b/perl/xs/XSBind.c @@ -15,10 +15,15 @@ */ #define C_LUCY_OBJ +#define C_LUCY_VTABLE +#define C_LUCY_LOCKFREEREGISTRY #define NEED_newRV_noinc #include "XSBind.h" +#include "Clownfish/Host.h" +#include "Clownfish/LockFreeRegistry.h" #include "Clownfish/Util/StringHelper.h" #include "Clownfish/Util/NumberUtils.h" +#include "Clownfish/Util/Memory.h" // Convert a Perl hash into a Clownfish Hash. Caller takes responsibility for // a refcount. @@ -579,4 +584,284 @@ XSBind_allot_params(SV** stack, int32_t start, int32_t num_stack_elems, ...) { return true; } +/*************************************************************************** + * The routines below are declared within the Clownfish core but left + * unimplemented and must be defined for each host language. + ***************************************************************************/ + +/**************************** Clownfish::Obj *******************************/ + +static void +S_lazy_init_host_obj(lucy_Obj *self) { + SV *inner_obj = newSV(0); + SvOBJECT_on(inner_obj); + PL_sv_objcount++; + SvUPGRADE(inner_obj, SVt_PVMG); + sv_setiv(inner_obj, PTR2IV(self)); + + // Connect class association. + lucy_CharBuf *class_name = Lucy_VTable_Get_Name(self->vtable); + HV *stash = gv_stashpvn((char*)Lucy_CB_Get_Ptr8(class_name), + Lucy_CB_Get_Size(class_name), TRUE); + SvSTASH_set(inner_obj, (HV*)SvREFCNT_inc(stash)); + + /* Up till now we've been keeping track of the refcount in + * self->ref.count. We're replacing ref.count with ref.host_obj, which + * will assume responsibility for maintaining the refcount. ref.host_obj + * starts off with a refcount of 1, so we need to transfer any refcounts + * in excess of that. */ + size_t old_refcount = self->ref.count; + self->ref.host_obj = inner_obj; + while (old_refcount > 1) { + SvREFCNT_inc_simple_void_NN(inner_obj); + old_refcount--; + } +} + +uint32_t +lucy_Obj_get_refcount(lucy_Obj *self) { + return self->ref.count < 4 + ? self->ref.count + : SvREFCNT((SV*)self->ref.host_obj); +} + +lucy_Obj* +lucy_Obj_inc_refcount(lucy_Obj *self) { + switch (self->ref.count) { + case 0: + CFISH_THROW(LUCY_ERR, "Illegal refcount of 0"); + break; // useless + case 1: + case 2: + self->ref.count++; + break; + case 3: + S_lazy_init_host_obj(self); + // fall through + default: + SvREFCNT_inc_simple_void_NN((SV*)self->ref.host_obj); + } + return self; +} + +uint32_t +lucy_Obj_dec_refcount(lucy_Obj *self) { + uint32_t modified_refcount = I32_MAX; + switch (self->ref.count) { + case 0: + CFISH_THROW(LUCY_ERR, "Illegal refcount of 0"); + break; // useless + case 1: + modified_refcount = 0; + Lucy_Obj_Destroy(self); + break; + case 2: + case 3: + modified_refcount = --self->ref.count; + break; + default: + modified_refcount = SvREFCNT((SV*)self->ref.host_obj) - 1; + // If the SV's refcount falls to 0, DESTROY will be invoked from + // Perl-space. + SvREFCNT_dec((SV*)self->ref.host_obj); + } + return modified_refcount; +} + +void* +lucy_Obj_to_host(lucy_Obj *self) { + if (self->ref.count < 4) { S_lazy_init_host_obj(self); } + return newRV_inc((SV*)self->ref.host_obj); +} + +/*************************** Clownfish::VTable ******************************/ + +lucy_Obj* +lucy_VTable_foster_obj(lucy_VTable *self, void *host_obj) { + lucy_Obj *obj + = (lucy_Obj*)lucy_Memory_wrapped_calloc(self->obj_alloc_size, 1); + SV *inner_obj = SvRV((SV*)host_obj); + obj->vtable = self; + sv_setiv(inner_obj, PTR2IV(obj)); + obj->ref.host_obj = inner_obj; + return obj; +} + +void +lucy_VTable_register_with_host(lucy_VTable *singleton, lucy_VTable *parent) { + // Register class with host. + lucy_Host_callback(LUCY_VTABLE, "_register", 2, + CFISH_ARG_OBJ("singleton", singleton), + CFISH_ARG_OBJ("parent", parent)); +} + +lucy_VArray* +lucy_VTable_fresh_host_methods(const lucy_CharBuf *class_name) { + return (lucy_VArray*)lucy_Host_callback_obj( + LUCY_VTABLE, + "fresh_host_methods", 1, + CFISH_ARG_STR("class_name", class_name)); +} + +lucy_CharBuf* +lucy_VTable_find_parent_class(const lucy_CharBuf *class_name) { + return lucy_Host_callback_str(LUCY_VTABLE, "find_parent_class", 1, + CFISH_ARG_STR("class_name", class_name)); +} + +void* +lucy_VTable_to_host(lucy_VTable *self) { + chy_bool_t first_time = self->ref.count < 4 ? true : false; + Lucy_VTable_To_Host_t to_host + = CFISH_SUPER_METHOD_PTR(LUCY_VTABLE, Lucy_VTable_To_Host); + SV *host_obj = (SV*)to_host(self); + if (first_time) { + SvSHARE((SV*)self->ref.host_obj); + } + return host_obj; +} + + +/***************************** Clownfish::Err *******************************/ + +// Anonymous XSUB helper for Err#trap(). It wraps the supplied C function +// so that it can be run inside a Perl eval block. +static SV *attempt_xsub = NULL; + +XS(lucy_Err_attempt_via_xs) { + dXSARGS; + CHY_UNUSED_VAR(cv); + SP -= items; + if (items != 2) { + CFISH_THROW(CFISH_ERR, "Usage: $sub->(routine, context)"); + }; + IV routine_iv = SvIV(ST(0)); + IV context_iv = SvIV(ST(1)); + Cfish_Err_Attempt_t routine = INT2PTR(Cfish_Err_Attempt_t, routine_iv); + void *context = INT2PTR(void*, context_iv); + routine(context); + XSRETURN(0); +} + +void +lucy_Err_init_class(void) { + char *file = (char*)__FILE__; + attempt_xsub = (SV*)newXS(NULL, lucy_Err_attempt_via_xs, file); +} + +lucy_Err* +lucy_Err_get_error() { + lucy_Err *error + = (lucy_Err*)lucy_Host_callback_obj(LUCY_ERR, "get_error", 0); + CFISH_DECREF(error); // Cancel out incref from callback. + return error; +} + +void +lucy_Err_set_error(lucy_Err *error) { + lucy_Host_callback(LUCY_ERR, "set_error", 1, + CFISH_ARG_OBJ("error", error)); + CFISH_DECREF(error); +} + +void +lucy_Err_do_throw(lucy_Err *err) { + dSP; + SV *error_sv = (SV*)Lucy_Err_To_Host(err); + CFISH_DECREF(err); + ENTER; + SAVETMPS; + PUSHMARK(SP); + XPUSHs(sv_2mortal(error_sv)); + PUTBACK; + call_pv("Clownfish::Err::do_throw", G_DISCARD); + FREETMPS; + LEAVE; +} + +void* +lucy_Err_to_host(lucy_Err *self) { + Lucy_Err_To_Host_t super_to_host + = CFISH_SUPER_METHOD_PTR(LUCY_ERR, Lucy_Err_To_Host); + SV *perl_obj = (SV*)super_to_host(self); + XSBind_enable_overload(perl_obj); + return perl_obj; +} + +void +lucy_Err_throw_mess(lucy_VTable *vtable, lucy_CharBuf *message) { + Lucy_Err_Make_t make + = CFISH_METHOD_PTR(CFISH_CERTIFY(vtable, LUCY_VTABLE), Lucy_Err_Make); + lucy_Err *err = (lucy_Err*)CFISH_CERTIFY(make(NULL), LUCY_ERR); + Lucy_Err_Cat_Mess(err, message); + CFISH_DECREF(message); + lucy_Err_do_throw(err); +} + +void +lucy_Err_warn_mess(lucy_CharBuf *message) { + SV *error_sv = XSBind_cb_to_sv(message); + CFISH_DECREF(message); + warn("%s", SvPV_nolen(error_sv)); + SvREFCNT_dec(error_sv); +} + +lucy_Err* +lucy_Err_trap(Cfish_Err_Attempt_t routine, void *context) { + lucy_Err *error = NULL; + SV *routine_sv = newSViv(PTR2IV(routine)); + SV *context_sv = newSViv(PTR2IV(context)); + dSP; + ENTER; + SAVETMPS; + PUSHMARK(SP); + EXTEND(SP, 2); + PUSHs(sv_2mortal(routine_sv)); + PUSHs(sv_2mortal(context_sv)); + PUTBACK; + + int count = call_sv(attempt_xsub, G_EVAL | G_DISCARD); + if (count != 0) { + lucy_CharBuf *mess + = lucy_CB_newf("'attempt' returned too many values: %i32", + (int32_t)count); + error = lucy_Err_new(mess); + } + else { + SV *dollar_at = get_sv("@", FALSE); + if (SvTRUE(dollar_at)) { + if (sv_isobject(dollar_at) + && sv_derived_from(dollar_at,"Clownfish::Err") + ) { + IV error_iv = SvIV(SvRV(dollar_at)); + error = INT2PTR(lucy_Err*, error_iv); + CFISH_INCREF(error); + } + else { + STRLEN len; + char *ptr = SvPVutf8(dollar_at, len); + lucy_CharBuf *mess = lucy_CB_new_from_trusted_utf8(ptr, len); + error = lucy_Err_new(mess); + } + } + } + FREETMPS; + LEAVE; + + return error; +} + +/*********************** Clownfish::LockFreeRegistry ************************/ + +void* +lucy_LFReg_to_host(lucy_LockFreeRegistry *self) { + chy_bool_t first_time = self->ref.count < 4 ? true : false; + Lucy_LFReg_To_Host_t to_host + = CFISH_SUPER_METHOD_PTR(LUCY_LOCKFREEREGISTRY, Lucy_LFReg_To_Host); + SV *host_obj = (SV*)to_host(self); + if (first_time) { + SvSHARE((SV*)self->ref.host_obj); + } + return host_obj; +}
