Qore Programming Language 1.19.2
Loading...
Searching...
No Matches
QoreObjectIntern.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 QoreObjectIntern.h
4
5 Qore Programming Language
6
7 Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the "Software"),
11 to deal in the Software without restriction, including without limitation
12 the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 and/or sell copies of the Software, and to permit persons to whom the
14 Software is furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26
27 Note that the Qore library is released under a choice of three open-source
28 licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
29 information.
30*/
31
32#ifndef _QORE_QOREOBJECTINTERN_H
33
34#define _QORE_QOREOBJECTINTERN_H
35
36#include "qore/intern/VRMutex.h"
37
38#include <cassert>
39#include <cstdlib>
40#include <cstring>
41#include <map>
42#include <set>
43#include <vector>
44
45//#define _QORE_CYCLE_CHECK 1
46#ifdef _QORE_CYCLE_CHECK
47#define QORE_DEBUG_OBJ_REFS 0
48#define QRO_LVL 0
49#else
50#define QORE_DEBUG_OBJ_REFS 5
51#define QRO_LVL 1
52#endif
53
54#include "qore/intern/QoreClassIntern.h"
55#include "qore/intern/RSection.h"
56#include "qore/intern/RSet.h"
57
58#define OS_OK 0
59#define OS_DELETED -1
60
61// object access constants
62#define QOA_OK 0
63#define QOA_PRIV_ERROR 1
64#define QOA_PUB_ERROR 2
65
66class LValueHelper;
67
68class lthash {
69public:
70 DLLLOCAL bool operator()(char* s1, char* s2) const {
71 return memcmp(s1, s2, SH_SIZE) < 0;
72 }
73};
74
75// per-class internal data
76typedef std::map<char*, QoreHashNode*, lthash> cdmap_t;
77
78/*
79 Qore internal class data is stored against the object with this data structure
80 against its qore_classid_t (class ID). In a class hierarchy, for private data
81 that is actually a C++ subclass of Qore parent classes, then we save the same
82 private data against the qore class IDs of the parent classes, but we set the
83 flag to true, meaning that we will not delete the private data when
84 the parent classes' destructors are run, but rather only when the subclass that
85 actually owns data has its turn to destroy private object data.
86
87 So basically, the second boolean flag just means - does this class ID actually
88 own the private data or not - if it's false, then it does not actually own the data,
89 but is compatible with the data, so parent class builtin (C++) methods will get
90 passed this private data as if it belonged to this class and as if it were saved
91 directly to the object in the class' constructor.
92
93 please note that this flag is called the "virtual" flag elsewhere in the code here,
94 meaning that the data only "virtually" belongs to the class
95 */
96typedef std::pair<AbstractPrivateData*, bool> private_pair_t;
97
98// mapping from qore class ID to the object data
99typedef std::map<qore_classid_t, private_pair_t> keymap_t;
100
101// for objects with multiple classes, private data has to be keyed
102class KeyList {
103private:
104 keymap_t keymap;
105
106public:
107 DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key) const {
108 keymap_t::const_iterator i = keymap.find(key);
109 if (i == keymap.end())
110 return 0;
111
112 AbstractPrivateData* apd = i->second.first;
113 apd->ref();
114 return apd;
115 }
116
117 DLLLOCAL void addToString(QoreString* str) const {
118 for (keymap_t::const_iterator i = keymap.begin(), e = keymap.end(); i != e; ++i)
119 str->sprintf("%d=<%p>, ", i->first, i->second.first);
120 }
121
122 DLLLOCAL void derefAll(ExceptionSink* xsink) const {
123 for (keymap_t::const_iterator i = keymap.begin(), e = keymap.end(); i != e; ++i)
124 if (!i->second.second)
125 i->second.first->deref(xsink);
126 }
127
128 DLLLOCAL AbstractPrivateData* getAndClearPtr(qore_classid_t key) {
129 keymap_t::iterator i = keymap.find(key);
130 //printd(5, "KeyList::getAndClearPtr this: %p, key: %d, end: %d\n", this, key, i == keymap.end());
131 if (i == keymap.end() || i->second.second) {
132 //printd(5, "KeyList::getAndClearPtr second: %d\n", i->second.second);
133 return nullptr;
134 }
135 //printd(5, "KeyList::getAndClearPtr first: %p\n", i->second.first);
136 // we must clear the private data when this function is called or a crash will result
137 AbstractPrivateData* rv = i->second.first;
138 keymap.erase(i);
139 return rv;
140 }
141
142 DLLLOCAL AbstractPrivateData* getAndRemovePtr(qore_classid_t key) {
143 keymap_t::iterator i = keymap.find(key);
144 //printd(5, "KeyList::getAndRemovePtr this: %p, key: %d, end: %d\n", this, key, i == keymap.end());
145 if (i == keymap.end() || i->second.second) {
146 //printd(5, "KeyList::getAndRemovePtr second: %d\n", i->second.second);
147 return 0;
148 }
149 AbstractPrivateData* rv = i->second.first;
150 //printd(5, "KeyList::getAndRemovePtr first: %p\n", i->second.first);
151 i->second.first = 0;
152 return rv;
153 }
154
155 DLLLOCAL void insert(qore_classid_t key, AbstractPrivateData* pd) {
156 assert(pd);
157 assert(keymap.find(key) == keymap.end());
158 //printd(5, "KeyList::insert this: %p, key: %d, pd: %p\n", this, key, pd);
159 keymap.insert(std::make_pair(key, std::make_pair(pd, false)));
160 }
161
162 DLLLOCAL void insertVirtual(qore_classid_t key, AbstractPrivateData* pd) {
163 assert(pd);
164 //printd(5, "KeyList::insertVirtual this: %p, key: %d, pd: %p, test: %d\n", this, key, pd,
165 // keymap.find(key) == keymap.end());
166 if (keymap.find(key) == keymap.end())
167 keymap.insert(std::make_pair(key, std::make_pair(pd, true)));
168 }
169};
170
171class VRMutex;
172
173class qore_object_private : public RObject {
174public:
175 const QoreClass* theclass;
176 int status = OS_OK;
177
178 KeyList* privateData = nullptr;
179 // member data
180 QoreHashNode* data;
181 QoreProgram* pgm;
182 cdmap_t* cdmap = nullptr;
183
184 // used for garbage collection
185 mutable unsigned obj_count = 0;
186
187 mutable VRMutex gate;
188
189 int scan_private_data = 0;
190
191 bool system_object, in_destructor;
192 bool recursive_ref_found;
193
194 QoreObject* obj;
195
196 DLLLOCAL qore_object_private(QoreObject* n_obj, const QoreClass *oc, QoreProgram* p, QoreHashNode* n_data);
197
198 DLLLOCAL ~qore_object_private();
199
200 DLLLOCAL void incScanPrivateData();
201 DLLLOCAL void decScanPrivateData();
202
203 DLLLOCAL void plusEquals(const AbstractQoreNode* v, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink) {
204 if (!v) {
205 return;
206 }
207
208 // do not need ensure_unique() for objects
209 if (v->getType() == NT_OBJECT) {
210 merge(*const_cast<QoreObject*>(reinterpret_cast<const QoreObject*>(v))->priv, vl, sdh, xsink);
211 } else if (v->getType() == NT_HASH) {
212 merge(reinterpret_cast<const QoreHashNode*>(v), vl, sdh, xsink);
213 }
214 }
215
216 DLLLOCAL void merge(qore_object_private& o, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink);
217
218 DLLLOCAL void merge(const QoreHashNode* h, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink);
219
220 DLLLOCAL void mergeIntern(ExceptionSink* xsink, const QoreHashNode* h, bool& check_recursive,
221 const qore_class_private* class_ctx, SafeDerefHelper& sdh, const QoreHashNode* new_internal_data = nullptr);
222
223 DLLLOCAL QoreHashNode* copyData(ExceptionSink* xsink) const;
224
225 DLLLOCAL int getLValue(const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove,
226 ExceptionSink* xsink);
227
228 DLLLOCAL QoreStringNode* firstKey(ExceptionSink* xsink) {
229 // get the current class context
230 const qore_class_private* class_ctx = runtime_get_class();
231 if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
232 class_ctx = nullptr;
233
234 QoreAutoVarRWReadLocker al(rml);
235
236 if (status == OS_DELETED) {
237 makeAccessDeletedObjectException(xsink, theclass->getName());
238 return nullptr;
239 }
240
241 if (class_ctx) {
242 const char* str = data->getFirstKey();
243 //printd(5, "qore_object_private::firstKey() got %p (%s)\n", str, str ? str : "<null>");
244 return !str ? nullptr : new QoreStringNode(str);
245 }
246
247 // get first accessible non-internal member
248 ConstHashIterator hi(data);
249 while (hi.next()) {
250 //printd(5, "qore_object_private::firstKey() checking '%s'\n", hi.getKey());
251 const qore_class_private* member_class_ctx = nullptr;
252 if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
253 return new QoreStringNode(hi.getKey());
254 //printd(5, "qore_object_private::firstKey() skipping '%s' (private)\n", hi.getKey());
255 }
256
257 return nullptr;
258 }
259
260 DLLLOCAL QoreStringNode* lastKey(ExceptionSink* xsink) {
261 // get the current class context
262 const qore_class_private* class_ctx = runtime_get_class();
263 if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
264 class_ctx = nullptr;
265
266 QoreAutoVarRWReadLocker al(rml);
267
268 if (status == OS_DELETED) {
269 makeAccessDeletedObjectException(xsink, theclass->getName());
270 return nullptr;
271 }
272
273 if (class_ctx) {
274 const char* str = data->getLastKey();
275 return !str ? nullptr : new QoreStringNode(str);
276 }
277
278 // get last accessible non-internal member
280 while (hi.next()) {
281 const qore_class_private* member_class_ctx = nullptr;
282 if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
283 return new QoreStringNode(hi.getKey());
284 }
285
286 return nullptr;
287 }
288
289 DLLLOCAL QoreHashNode* getSlice(const QoreListNode* l, ExceptionSink* xsink) const;
290
291 DLLLOCAL int checkMemberAccessIntern(const char* mem, bool has_public_members,
292 const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx) const {
293 assert(!member_class_ctx);
294
295 const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
296 const QoreMemberInfo* info = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
297 if (!info) {
298 return has_public_members ? QOA_PUB_ERROR : QOA_OK;
299 }
300 member_class_ctx = info->getClassContext(class_ctx);
301 return ((info->access > Public) && !class_ctx) ? QOA_PRIV_ERROR : QOA_OK;
302 }
303
304 // must be called in the object read lock
305 DLLLOCAL const QoreHashNode* getInternalData(const qore_class_private* class_ctx) const {
306 if (!cdmap)
307 return nullptr;
308 cdmap_t::const_iterator i = cdmap->find(class_ctx->getHash());
309 return i != cdmap->end() ? i->second : nullptr;
310 }
311
312 // must be called in the object read lock
313 DLLLOCAL QoreHashNode* getInternalData(const qore_class_private* class_ctx) {
314 if (!cdmap)
315 return nullptr;
316 cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
317 return i != cdmap->end() ? i->second : nullptr;
318 }
319
320 // must be called in the object write lock
321 DLLLOCAL QoreHashNode* getCreateInternalData(const qore_class_private* class_ctx) {
322 if (cdmap) {
323 cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
324 if (i != cdmap->end())
325 return i->second;
326 } else
327 cdmap = new cdmap_t;
328
329 QoreHashNode* id = new QoreHashNode(autoTypeInfo);
330 cdmap->insert(cdmap_t::value_type(class_ctx->getHash(), id));
331 return id;
332 }
333
334 // issue #3901: perform a shallow copy of private:internal data when executing a copy method
335 DLLLOCAL void copyInternalData(const qore_object_private& old) {
336 assert(!cdmap);
337 if (!old.cdmap) {
338 return;
339 }
340 cdmap = new cdmap_t;
341 for (auto& i : *old.cdmap) {
342 cdmap->insert(cdmap_t::value_type(i.first, i.second->copy()));
343 }
344 }
345
346 DLLLOCAL void setValue(const char* key, QoreValue val, ExceptionSink* xsink);
347
348 DLLLOCAL void setValueIntern(const qore_class_private* class_ctx, const char* key, QoreValue val,
349 ExceptionSink* xsink);
350
351 DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx,
352 const qore_class_private*& member_class_ctx) const;
353
354 DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx,
355 const qore_class_private*& member_class_ctx, ExceptionSink* xsink) const {
356 int rc = checkMemberAccess(mem, class_ctx, member_class_ctx);
357 if (!rc) {
358 return 0;
359 }
360
361 if (rc == QOA_PRIV_ERROR) {
362 doPrivateException(mem, xsink);
363 } else {
364 doPublicException(mem, xsink);
365 }
366 return -1;
367 }
368
369 DLLLOCAL int checkMemberAccessGetTypeInfo(ExceptionSink* xsink, const char* mem,
370 const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx,
371 const QoreTypeInfo*& typeInfo) const {
372 assert(!member_class_ctx);
373 const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
374 const QoreMemberInfo* mi = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
375 if (mi) {
376 if (mi->access > Public && !class_ctx) {
377 doPrivateException(mem, xsink);
378 return -1;
379 }
380
381 member_class_ctx = mi->getClassContext(class_ctx);
382 typeInfo = mi->getTypeInfo();
383 return 0;
384 }
385
386 // member is not declared
387 if (theclass->hasPublicMembersInHierarchy()) {
388 doPublicException(mem, xsink);
389 return -1;
390 }
391 return 0;
392 }
393
394 DLLLOCAL QoreValue takeMember(ExceptionSink* xsink, const char* mem, bool check_access = true);
395
396 DLLLOCAL QoreValue takeMember(LValueHelper& lvh, const char* mem);
397
398 DLLLOCAL void takeMembers(QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l);
399
400 DLLLOCAL QoreValue getReferencedMemberNoMethod(const char* mem, ExceptionSink* xsink) const;
401
402 // lock not held on entry
403 DLLLOCAL void doDeleteIntern(ExceptionSink* xsink);
404
405 DLLLOCAL void cleanup(ExceptionSink* xsink, QoreHashNode* td, cdmap_t* cdm) {
406 if (privateData) {
407 printd(5, "qore_object_private::cleanup() this: %p privateData: %p\n", this, privateData);
408 delete privateData;
409#ifdef DEBUG
410 privateData = nullptr;
411#endif
412 }
413
414 td->clear(xsink, true);
415 td->deref(xsink);
416
417 if (cdm) {
418 for (auto& i : *cdm) {
419 i.second->clear(xsink, true);
420 i.second->deref(xsink);
421 }
422 delete cdm;
423 }
424 }
425
426 // this method is called when there is an exception in a constructor and the object should be deleted
427 DLLLOCAL void obliterate(ExceptionSink* xsink) {
428 printd(5, "qore_object_private::obliterate() obj: %p class: %s %d->%d\n", obj, theclass->getName(),
429 obj->references.load(), obj->references.load() - 1);
430
431#ifdef QORE_DEBUG_OBJ_REFS
432 printd(QORE_DEBUG_OBJ_REFS, "qore_object_private::obliterate() obj: %p class: %s: references %d->%d\n", obj,
433 theclass->getName(), obj->references.load(), obj->references.load() - 1);
434#endif
435
436 {
437 AutoLocker slr(rlck);
438 if (--obj->references)
439 return;
440 }
441
442 {
443 QoreSafeVarRWWriteLocker sl(rml);
444
445 if (in_destructor || status != OS_OK) {
446 printd(5, "qore_object_private::obliterate() obj: %p data: %p in_destructor: %d status: %d\n", obj,
447 data, in_destructor, status);
448 //printd(5, "Object lock %p unlocked (safe)\n", &rml);
449 sl.unlock();
450 tDeref();
451 return;
452 }
453
454 //printd(5, "Object lock %p locked (safe)\n", &rml);
455 printd(5, "qore_object_private::obliterate() obj: %p class: %s\n", obj, theclass->getName());
456
457 status = OS_DELETED;
458 cdmap_t* cdm = cdmap;
459 cdmap = nullptr;
460 QoreHashNode* td = data;
461 data = nullptr;
462
463 removeInvalidateRSetIntern();
464
465 //printd(5, "Object lock %p unlocked (safe)\n", &rml);
466 sl.unlock();
467
468 if (privateData)
469 privateData->derefAll(xsink);
470
471 cleanup(xsink, td, cdm);
472 }
473 tDeref();
474 }
475
476 DLLLOCAL void doPrivateException(const char* mem, ExceptionSink* xsink) const {
477 xsink->raiseException("PRIVATE-MEMBER", "'%s' is a private member of class '%s'", mem, theclass->getName());
478 }
479
480 DLLLOCAL void doPublicException(const char* mem, ExceptionSink* xsink) const {
481 xsink->raiseException("INVALID-MEMBER", "'%s' is not a registered member of class '%s'", mem,
482 theclass->getName());
483 }
484
485 DLLLOCAL virtual const char* getName() const {
486 return theclass->getName();
487 }
488
489 DLLLOCAL virtual void deleteObject() {
490 delete obj;
491 }
492
493 DLLLOCAL virtual bool isValidImpl() const {
494 if (status != OS_OK || in_destructor) {
495 printd(QRO_LVL, "qore_object_intern::isValidImpl() this: %p cannot delete graph obj status: %d "
496 "in_destructor: %d\n", this, status, in_destructor);
497 return false;
498 }
499 return true;
500 }
501
502 DLLLOCAL virtual bool scanMembersIntern(RSetHelper& rsh, QoreHashNode* odata);
503
504 DLLLOCAL virtual bool scanMembers(RSetHelper& rsh);
505
506 // always called in the rsection lock
507 DLLLOCAL virtual bool needsScan(bool scan_now) {
508 assert(rml.hasRSectionLock());
509 printd(5, "qore_object_private::needsScan() scan_count: %d scan_private_data: %d scan_now: %d\n",
510 getScanCount(), scan_private_data, scan_now);
511
512 // the status cannot change while this lock is held
513 if ((!getScanCount() && !scan_private_data) || status != OS_OK) {
514 return false;
515 }
516
517 {
518 AutoLocker al(rlck);
519 if (deferred_scan) {
520 if (!rrefs && scan_now) {
521 deferred_scan = false;
522 return true;
523 }
524 return false;
525 }
526 if (!rrefs) {
527 return true;
528 }
529 deferred_scan = true;
530 // if there is no rset, our job is done
531 if (!rset && !scan_private_data) {
532 return false;
533 }
534 // if we have an rset, then we need to invalidate it and ensure that
535 // rrefs does not go to zero until this is done
536 rref_wait = true;
537 }
538
539 removeInvalidateRSetIntern();
540 AutoLocker al(rlck);
541 rref_wait = false;
542 if (rref_waiting) {
543 rcond.broadcast();
544 }
545
546 return false;
547 }
548
549 DLLLOCAL void mergeDataToHash(QoreHashNode* hash, SafeDerefHelper& sdh, ExceptionSink* xsink) const;
550
551 DLLLOCAL void setPrivate(qore_classid_t key, AbstractPrivateData* pd) {
552 if (!privateData) {
553 privateData = new KeyList;
554 }
555 printd(5, "qore_object_private::setPrivate() this: %p 2:privateData: %p (%s) key: %d pd: %p\n", this,
556 privateData, theclass->getName(), key, pd);
557 privateData->insert(key, pd);
558 addVirtualPrivateData(key, pd);
559 }
560
561 // add virtual IDs for private data to class list
562 DLLLOCAL void addVirtualPrivateData(qore_classid_t key, AbstractPrivateData* apd);
563
564 DLLLOCAL AbstractPrivateData* getAndRemovePrivateData(qore_classid_t key, ExceptionSink* xsink) {
565 QoreSafeVarRWWriteLocker sl(rml);
566 return privateData ? privateData->getAndRemovePtr(key) : nullptr;
567 }
568
569 DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
570
571 DLLLOCAL AbstractPrivateData* tryGetReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
572
573 DLLLOCAL QoreValue evalBuiltinMethodWithPrivateData(const QoreMethod& method,
574 const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags,
575 ExceptionSink* xsink);
576
577 // no locking necessary; if class_ctx is non-null, an internal member is being initialized
578 DLLLOCAL QoreValue& getMemberValueRefForInitialization(const char* member, const qore_class_private* class_ctx);
579
581
586 DLLLOCAL QoreHashNode* getRuntimeMemberHash(ExceptionSink* xsink) const;
587
588 DLLLOCAL void incScanCount(int dt) {
589 assert(dt);
590 assert(obj_count || dt > 0);
591 //printd(5, "qore_object_private::incScanCount() this: %p dt: %d: %d -> %d\n", this, dt, obj_count, obj_count
592 // + dt);
593 obj_count += dt;
594 }
595
596 DLLLOCAL unsigned getScanCount() const {
597 return obj_count;
598 }
599
600 DLLLOCAL VRMutex* getGate() const {
601 return &gate;
602 }
603
604 /*
605 DLLLOCAL static bool hackId(const QoreObject& obj) {
606 if (!obj.priv->data)
607 return false;
608 const AbstractQoreNode* n = obj.priv->data->getKeyValue("name");
609 if (n && n->getType() == NT_STRING && strstr(reinterpret_cast<const QoreStringNode*>(n)->getBuffer(),
610 "http-test"))
611 return true;
612 return false;
613 }
614 */
615
616 // custom reference handler - unlocked
619 DLLLOCAL void customRefIntern(bool real);
620
621 // custom dereference handler - unlocked
624 DLLLOCAL void customDeref(bool real, ExceptionSink* xsink);
625
626 DLLLOCAL int startCall(const char* mname, ExceptionSink* xsink);
627
628 DLLLOCAL void endCall(ExceptionSink* xsink);
629
630 // increments the real reference count without incrementing the actual reference count
631 // (i.e. turns the current not real reference into a "real" reference; one that cannot
632 // participate in recursive graphs)
633 DLLLOCAL void setRealReference();
634
635 // decrements the real reference count without decrementing the actual reference count
636 DLLLOCAL void unsetRealReference();
637
638 DLLLOCAL const char* getClassName() const {
639 return theclass->getName();
640 }
641
642 DLLLOCAL static QoreValue evalBuiltinMethodWithPrivateData(QoreObject& obj, const QoreMethod& method,
643 const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags,
644 ExceptionSink* xsink) {
645 return obj.priv->evalBuiltinMethodWithPrivateData(method, meth, args, rtflags, xsink);
646 }
647
648 DLLLOCAL static qore_object_private* get(QoreObject& obj) {
649 return obj.priv;
650 }
651
652 DLLLOCAL static const qore_object_private* get(const QoreObject& obj) {
653 return obj.priv;
654 }
655
656 DLLLOCAL static QoreValue takeMember(QoreObject& obj, ExceptionSink* xsink, const char* mem,
657 bool check_access = true) {
658 return obj.priv->takeMember(xsink, mem, check_access);
659 }
660
661 DLLLOCAL static QoreValue takeMember(QoreObject& obj, LValueHelper& lvh, const char* mem) {
662 return obj.priv->takeMember(lvh, mem);
663 }
664
665 DLLLOCAL static void takeMembers(QoreObject& o, QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l) {
666 o.priv->takeMembers(rv, lvh, l);
667 }
668
669 DLLLOCAL static int getLValue(const QoreObject& obj, const char* key, LValueHelper& lvh,
670 const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink) {
671 return obj.priv->getLValue(key, lvh, class_ctx, for_remove, xsink);
672 }
673
674 DLLLOCAL static QoreStringNode* firstKey(QoreObject* obj, ExceptionSink* xsink) {
675 return obj->priv->firstKey(xsink);
676 }
677
678 DLLLOCAL static QoreStringNode* lastKey(QoreObject* obj, ExceptionSink* xsink) {
679 return obj->priv->lastKey(xsink);
680 }
681
682 DLLLOCAL static unsigned getScanCount(const QoreObject& o) {
683 return o.priv->getScanCount();
684 }
685
686 DLLLOCAL static void incScanCount(const QoreObject& o, int dt) {
687 o.priv->incScanCount(dt);
688 }
689};
690
691class qore_object_lock_handoff_helper {
692private:
693 qore_object_private* pobj;
694 AutoVLock& vl;
695
696public:
697 DLLLOCAL qore_object_lock_handoff_helper(qore_object_private* n_pobj, AutoVLock& n_vl) : pobj(n_pobj), vl(n_vl) {
698 if (pobj->obj == vl.getObject()) {
699 assert(vl.getRWL() == &pobj->rml);
700 vl.clear();
701 return;
702 }
703
704 // reference current object
705 pobj->obj->tRef();
706
707 // unlock previous lock and release from AutoVLock structure
708 vl.del();
709
710 // lock current object
711 pobj->rml.wrlock();
712 }
713
714 DLLLOCAL ~qore_object_lock_handoff_helper() {
715 // unlock if lock not saved in AutoVLock structure
716 if (pobj) {
717 //printd(5, "Object lock %p unlocked (handoff)\n", &pobj->rml);
718 pobj->rml.unlock();
719 pobj->obj->tDeref();
720 }
721 }
722
723 DLLLOCAL void stayLocked() {
724 vl.set(pobj->obj, &pobj->rml);
725 pobj = nullptr;
726 }
727};
728
729#endif
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
DLLLOCAL void ref() const
increments the reference count of the object
Definition: AbstractPrivateData.h:51
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:57
DLLLOCAL qore_type_t getType() const
returns the data type
Definition: AbstractQoreNode.h:175
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false,...
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack,...
Definition: QoreThreadLock.h:136
AutoVLock is a container for safely managing global variable and object lock handovers,...
Definition: AutoVLock.h:80
DLLEXPORT void del()
manually releases the lock currently held
DLLLOCAL void clear()
leaves the lock locked and the object referenced and clears the object and lock pointers
DLLLOCAL QoreObject * getObject() const
gets the current object
DLLLOCAL void set(QoreVarRWLock *n_rwl)
sets the current lock
DLLLOCAL QoreVarRWLock * getRWL() const
gets the current read-write lock
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:590
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
defines a Qore-language class
Definition: QoreClass.h:253
DLLEXPORT bool hasPublicMembersInHierarchy() const
returns true if the class has any publicly-declared members
DLLEXPORT const char * getName() const
returns the class name
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
DLLEXPORT const char * getFirstKey() const
returns the cstring value of the first key in the hash
DLLEXPORT const char * getLastKey() const
returns the cstring value of the last key in the hash
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
a method in a QoreClass
Definition: QoreClass.h:139
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:60
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:128
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
reverse constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:667
Helps dereference values outside of locks.
Definition: QoreLibIntern.h:543
uint64_t q_rt_flags_t
runtime code execution flags
Definition: common.h:263
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:276