| /* 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 "Lucy/Object/Obj.h" |
| #include "Lucy/Object/CharBuf.h" |
| #include "Lucy/Object/Err.h" |
| #include "Lucy/Object/VTable.h" |
| #include "Lucy/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); |
| } |
| |
| |