Qore Programming Language  1.12.0
QoreObjectIntern.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreObjectIntern.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2022 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 
66 class LValueHelper;
67 
68 class lthash {
69 public:
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
76 typedef 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  */
96 typedef std::pair<AbstractPrivateData*, bool> private_pair_t;
97 
98 // mapping from qore class ID to the object data
99 typedef std::map<qore_classid_t, private_pair_t> keymap_t;
100 
101 // for objects with multiple classes, private data has to be keyed
102 class KeyList {
103 private:
104  keymap_t keymap;
105 
106 public:
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, keymap.find(key) == keymap.end());
165  if (keymap.find(key) == keymap.end())
166  keymap.insert(std::make_pair(key, std::make_pair(pd, true)));
167  }
168 };
169 
170 class VRMutex;
171 
172 class qore_object_private : public RObject {
173 public:
174  const QoreClass* theclass;
175  int status = OS_OK;
176 
177  KeyList* privateData = nullptr;
178  // member data
179  QoreHashNode* data;
180  QoreProgram* pgm;
181  cdmap_t* cdmap = nullptr;
182 
183  // used for garbage collection
184  mutable unsigned obj_count = 0;
185 
186  mutable VRMutex gate;
187 
188  int scan_private_data = 0;
189 
190  bool system_object, in_destructor;
191  bool recursive_ref_found;
192 
193  QoreObject* obj;
194 
195  DLLLOCAL qore_object_private(QoreObject* n_obj, const QoreClass *oc, QoreProgram* p, QoreHashNode* n_data);
196 
197  DLLLOCAL ~qore_object_private();
198 
199  DLLLOCAL void incScanPrivateData();
200  DLLLOCAL void decScanPrivateData();
201 
202  DLLLOCAL void plusEquals(const AbstractQoreNode* v, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink) {
203  if (!v) {
204  return;
205  }
206 
207  // do not need ensure_unique() for objects
208  if (v->getType() == NT_OBJECT) {
209  merge(*const_cast<QoreObject*>(reinterpret_cast<const QoreObject*>(v))->priv, vl, sdh, xsink);
210  } else if (v->getType() == NT_HASH) {
211  merge(reinterpret_cast<const QoreHashNode*>(v), vl, sdh, xsink);
212  }
213  }
214 
215  DLLLOCAL void merge(qore_object_private& o, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink);
216 
217  DLLLOCAL void merge(const QoreHashNode* h, AutoVLock& vl, SafeDerefHelper& sdh, ExceptionSink* xsink);
218 
219  DLLLOCAL void mergeIntern(ExceptionSink* xsink, const QoreHashNode* h, bool& check_recursive,
220  const qore_class_private* class_ctx, SafeDerefHelper& sdh, const QoreHashNode* new_internal_data = nullptr);
221 
222  DLLLOCAL QoreHashNode* copyData(ExceptionSink* xsink) const;
223 
224  DLLLOCAL int getLValue(const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink);
225 
226  DLLLOCAL QoreStringNode* firstKey(ExceptionSink* xsink) {
227  // get the current class context
228  const qore_class_private* class_ctx = runtime_get_class();
229  if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
230  class_ctx = nullptr;
231 
232  QoreAutoVarRWReadLocker al(rml);
233 
234  if (status == OS_DELETED) {
235  makeAccessDeletedObjectException(xsink, theclass->getName());
236  return nullptr;
237  }
238 
239  if (class_ctx) {
240  const char* str = data->getFirstKey();
241  //printd(5, "qore_object_private::firstKey() got %p (%s)\n", str, str ? str : "<null>");
242  return !str ? nullptr : new QoreStringNode(str);
243  }
244 
245  // get first accessible non-internal member
246  ConstHashIterator hi(data);
247  while (hi.next()) {
248  //printd(5, "qore_object_private::firstKey() checking '%s'\n", hi.getKey());
249  const qore_class_private* member_class_ctx = nullptr;
250  if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
251  return new QoreStringNode(hi.getKey());
252  //printd(5, "qore_object_private::firstKey() skipping '%s' (private)\n", hi.getKey());
253  }
254 
255  return nullptr;
256  }
257 
258  DLLLOCAL QoreStringNode* lastKey(ExceptionSink* xsink) {
259  // get the current class context
260  const qore_class_private* class_ctx = runtime_get_class();
261  if (class_ctx && !qore_class_private::runtimeCheckPrivateClassAccess(*theclass, class_ctx))
262  class_ctx = nullptr;
263 
264  QoreAutoVarRWReadLocker al(rml);
265 
266  if (status == OS_DELETED) {
267  makeAccessDeletedObjectException(xsink, theclass->getName());
268  return nullptr;
269  }
270 
271  if (class_ctx) {
272  const char* str = data->getLastKey();
273  return !str ? nullptr : new QoreStringNode(str);
274  }
275 
276  // get last accessible non-internal member
277  ReverseConstHashIterator hi(data);
278  while (hi.next()) {
279  const qore_class_private* member_class_ctx = nullptr;
280  if (!checkMemberAccessIntern(hi.getKey(), false, class_ctx, member_class_ctx))
281  return new QoreStringNode(hi.getKey());
282  }
283 
284  return nullptr;
285  }
286 
287  DLLLOCAL QoreHashNode* getSlice(const QoreListNode* l, ExceptionSink* xsink) const;
288 
289  DLLLOCAL int checkMemberAccessIntern(const char* mem, bool has_public_members, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx) const {
290  assert(!member_class_ctx);
291 
292  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
293  const QoreMemberInfo* info = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
294  if (!info) {
295  return has_public_members ? QOA_PUB_ERROR : QOA_OK;
296  }
297  member_class_ctx = info->getClassContext(class_ctx);
298  return ((info->access > Public) && !class_ctx) ? QOA_PRIV_ERROR : QOA_OK;
299  }
300 
301  // must be called in the object read lock
302  DLLLOCAL const QoreHashNode* getInternalData(const qore_class_private* class_ctx) const {
303  if (!cdmap)
304  return nullptr;
305  cdmap_t::const_iterator i = cdmap->find(class_ctx->getHash());
306  return i != cdmap->end() ? i->second : nullptr;
307  }
308 
309  // must be called in the object read lock
310  DLLLOCAL QoreHashNode* getInternalData(const qore_class_private* class_ctx) {
311  if (!cdmap)
312  return nullptr;
313  cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
314  return i != cdmap->end() ? i->second : nullptr;
315  }
316 
317  // must be called in the object write lock
318  DLLLOCAL QoreHashNode* getCreateInternalData(const qore_class_private* class_ctx) {
319  if (cdmap) {
320  cdmap_t::iterator i = cdmap->find(class_ctx->getHash());
321  if (i != cdmap->end())
322  return i->second;
323  } else
324  cdmap = new cdmap_t;
325 
326  QoreHashNode* id = new QoreHashNode(autoTypeInfo);
327  cdmap->insert(cdmap_t::value_type(class_ctx->getHash(), id));
328  return id;
329  }
330 
331  // issue #3901: perform a shallow copy of private:internal data when executing a copy method
332  DLLLOCAL void copyInternalData(const qore_object_private& old) {
333  assert(!cdmap);
334  if (!old.cdmap) {
335  return;
336  }
337  cdmap = new cdmap_t;
338  for (auto& i : *old.cdmap) {
339  cdmap->insert(cdmap_t::value_type(i.first, i.second->copy()));
340  }
341  }
342 
343  DLLLOCAL void setValue(const char* key, QoreValue val, ExceptionSink* xsink);
344 
345  DLLLOCAL void setValueIntern(const qore_class_private* class_ctx, const char* key, QoreValue val, ExceptionSink* xsink);
346 
347  DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx,
348  const qore_class_private*& member_class_ctx) const;
349 
350  DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx,
351  const qore_class_private*& member_class_ctx, ExceptionSink* xsink) const {
352  int rc = checkMemberAccess(mem, class_ctx, member_class_ctx);
353  if (!rc) {
354  return 0;
355  }
356 
357  if (rc == QOA_PRIV_ERROR) {
358  doPrivateException(mem, xsink);
359  } else {
360  doPublicException(mem, xsink);
361  }
362  return -1;
363  }
364 
365  DLLLOCAL int checkMemberAccessGetTypeInfo(ExceptionSink* xsink, const char* mem, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx, const QoreTypeInfo*& typeInfo) const {
366  assert(!member_class_ctx);
367  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
368  const QoreMemberInfo* mi = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
369  if (mi) {
370  if (mi->access > Public && !class_ctx) {
371  doPrivateException(mem, xsink);
372  return -1;
373  }
374 
375  member_class_ctx = mi->getClassContext(class_ctx);
376  typeInfo = mi->getTypeInfo();
377  return 0;
378  }
379 
380  // member is not declared
381  if (theclass->hasPublicMembersInHierarchy()) {
382  doPublicException(mem, xsink);
383  return -1;
384  }
385  return 0;
386  }
387 
388  DLLLOCAL QoreValue takeMember(ExceptionSink* xsink, const char* mem, bool check_access = true);
389 
390  DLLLOCAL QoreValue takeMember(LValueHelper& lvh, const char* mem);
391 
392  DLLLOCAL void takeMembers(QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l);
393 
394  DLLLOCAL QoreValue getReferencedMemberNoMethod(const char* mem, ExceptionSink* xsink) const;
395 
396  // lock not held on entry
397  DLLLOCAL void doDeleteIntern(ExceptionSink* xsink);
398 
399  DLLLOCAL void cleanup(ExceptionSink* xsink, QoreHashNode* td, cdmap_t* cdm) {
400  if (privateData) {
401  printd(5, "qore_object_private::cleanup() this: %p privateData: %p\n", this, privateData);
402  delete privateData;
403 #ifdef DEBUG
404  privateData = nullptr;
405 #endif
406  }
407 
408  td->clear(xsink, true);
409  td->deref(xsink);
410 
411  if (cdm) {
412  for (auto& i : *cdm) {
413  i.second->clear(xsink, true);
414  i.second->deref(xsink);
415  }
416  delete cdm;
417  }
418  }
419 
420  // this method is called when there is an exception in a constructor and the object should be deleted
421  DLLLOCAL void obliterate(ExceptionSink* xsink) {
422  printd(5, "qore_object_private::obliterate() obj: %p class: %s %d->%d\n", obj, theclass->getName(), obj->references.load(), obj->references.load() - 1);
423 
424 #ifdef QORE_DEBUG_OBJ_REFS
425  printd(QORE_DEBUG_OBJ_REFS, "qore_object_private::obliterate() obj: %p class: %s: references %d->%d\n", obj, theclass->getName(), obj->references.load(), obj->references.load() - 1);
426 #endif
427 
428  {
429  AutoLocker slr(rlck);
430  if (--obj->references)
431  return;
432  }
433 
434  {
435  QoreSafeVarRWWriteLocker sl(rml);
436 
437  if (in_destructor || status != OS_OK) {
438  printd(5, "qore_object_private::obliterate() obj: %p data: %p in_destructor: %d status: %d\n", obj, data, in_destructor, status);
439  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
440  sl.unlock();
441  tDeref();
442  return;
443  }
444 
445  //printd(5, "Object lock %p locked (safe)\n", &rml);
446  printd(5, "qore_object_private::obliterate() obj: %p class: %s\n", obj, theclass->getName());
447 
448  status = OS_DELETED;
449  cdmap_t* cdm = cdmap;
450  cdmap = nullptr;
451  QoreHashNode* td = data;
452  data = nullptr;
453 
454  removeInvalidateRSetIntern();
455 
456  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
457  sl.unlock();
458 
459  if (privateData)
460  privateData->derefAll(xsink);
461 
462  cleanup(xsink, td, cdm);
463  }
464  tDeref();
465  }
466 
467  DLLLOCAL void doPrivateException(const char* mem, ExceptionSink* xsink) const {
468  xsink->raiseException("PRIVATE-MEMBER", "'%s' is a private member of class '%s'", mem, theclass->getName());
469  }
470 
471  DLLLOCAL void doPublicException(const char* mem, ExceptionSink* xsink) const {
472  xsink->raiseException("INVALID-MEMBER", "'%s' is not a registered member of class '%s'", mem, theclass->getName());
473  }
474 
475  DLLLOCAL virtual const char* getName() const {
476  return theclass->getName();
477  }
478 
479  DLLLOCAL virtual void deleteObject() {
480  delete obj;
481  }
482 
483  DLLLOCAL virtual bool isValidImpl() const {
484  if (status != OS_OK || in_destructor) {
485  printd(QRO_LVL, "qore_object_intern::isValidImpl() this: %p cannot delete graph obj status: %d in_destructor: %d\n", this, status, in_destructor);
486  return false;
487  }
488  return true;
489  }
490 
491  DLLLOCAL virtual bool scanMembersIntern(RSetHelper& rsh, QoreHashNode* odata);
492 
493  DLLLOCAL virtual bool scanMembers(RSetHelper& rsh);
494 
495  // always called in the rsection lock
496  DLLLOCAL virtual bool needsScan(bool scan_now) {
497  assert(rml.hasRSectionLock());
498  printd(5, "qore_object_private::needsScan() scan_count: %d scan_private_data: %d scan_now: %d\n",
499  getScanCount(), scan_private_data, scan_now);
500 
501  // the status cannot change while this lock is held
502  if ((!getScanCount() && !scan_private_data) || status != OS_OK) {
503  return false;
504  }
505 
506  {
507  AutoLocker al(rlck);
508  if (deferred_scan) {
509  if (!rrefs && scan_now) {
510  deferred_scan = false;
511  return true;
512  }
513  return false;
514  }
515  if (!rrefs) {
516  return true;
517  }
518  deferred_scan = true;
519  // if there is no rset, our job is done
520  if (!rset && !scan_private_data) {
521  return false;
522  }
523  // if we have an rset, then we need to invalidate it and ensure that
524  // rrefs does not go to zero until this is done
525  rref_wait = true;
526  }
527 
528  removeInvalidateRSetIntern();
529  AutoLocker al(rlck);
530  rref_wait = false;
531  if (rref_waiting) {
532  rcond.broadcast();
533  }
534 
535  return false;
536  }
537 
538  DLLLOCAL void mergeDataToHash(QoreHashNode* hash, SafeDerefHelper& sdh, ExceptionSink* xsink) const;
539 
540  DLLLOCAL void setPrivate(qore_classid_t key, AbstractPrivateData* pd) {
541  if (!privateData) {
542  privateData = new KeyList;
543  }
544  printd(5, "qore_object_private::setPrivate() this: %p 2:privateData: %p (%s) key: %d pd: %p\n", this, privateData, theclass->getName(), key, pd);
545  privateData->insert(key, pd);
546  addVirtualPrivateData(key, pd);
547  }
548 
549  // add virtual IDs for private data to class list
550  DLLLOCAL void addVirtualPrivateData(qore_classid_t key, AbstractPrivateData* apd);
551 
552  DLLLOCAL AbstractPrivateData* getAndRemovePrivateData(qore_classid_t key, ExceptionSink* xsink) {
553  QoreSafeVarRWWriteLocker sl(rml);
554  return privateData ? privateData->getAndRemovePtr(key) : nullptr;
555  }
556 
557  DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
558 
559  DLLLOCAL AbstractPrivateData* tryGetReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
560 
561  DLLLOCAL QoreValue evalBuiltinMethodWithPrivateData(const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink);
562 
563  // no locking necessary; if class_ctx is non-null, an internal member is being initialized
564  DLLLOCAL QoreValue& getMemberValueRefForInitialization(const char* member, const qore_class_private* class_ctx);
565 
567 
571  DLLLOCAL QoreHashNode* getRuntimeMemberHash(ExceptionSink* xsink) const;
572 
573  DLLLOCAL void incScanCount(int dt) {
574  assert(dt);
575  assert(obj_count || dt > 0);
576  //printd(5, "qore_object_private::incScanCount() this: %p dt: %d: %d -> %d\n", this, dt, obj_count, obj_count + dt);
577  obj_count += dt;
578  }
579 
580  DLLLOCAL unsigned getScanCount() const {
581  return obj_count;
582  }
583 
584  DLLLOCAL VRMutex* getGate() const {
585  return &gate;
586  }
587 
588  /*
589  DLLLOCAL static bool hackId(const QoreObject& obj) {
590  if (!obj.priv->data)
591  return false;
592  const AbstractQoreNode* n = obj.priv->data->getKeyValue("name");
593  if (n && n->getType() == NT_STRING && strstr(reinterpret_cast<const QoreStringNode*>(n)->getBuffer(), "http-test"))
594  return true;
595  return false;
596  }
597  */
598 
599  // custom reference handler - unlocked
602  DLLLOCAL void customRefIntern(bool real);
603 
604  // custom dereference handler - unlocked
607  DLLLOCAL void customDeref(bool real, ExceptionSink* xsink);
608 
609  DLLLOCAL int startCall(const char* mname, ExceptionSink* xsink);
610 
611  DLLLOCAL void endCall(ExceptionSink* xsink);
612 
613  // increments the real reference count without incrementing the actual reference count
614  // (i.e. turns the current not real reference into a "real" reference; one that cannot
615  // participate in recursive graphs)
616  DLLLOCAL void setRealReference();
617 
618  // decrements the real reference count without decrementing the actual reference count
619  DLLLOCAL void unsetRealReference();
620 
621  DLLLOCAL const char* getClassName() const {
622  return theclass->getName();
623  }
624 
625  DLLLOCAL static QoreValue evalBuiltinMethodWithPrivateData(QoreObject& obj, const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) {
626  return obj.priv->evalBuiltinMethodWithPrivateData(method, meth, args, rtflags, xsink);
627  }
628 
629  DLLLOCAL static qore_object_private* get(QoreObject& obj) {
630  return obj.priv;
631  }
632 
633  DLLLOCAL static const qore_object_private* get(const QoreObject& obj) {
634  return obj.priv;
635  }
636 
637  DLLLOCAL static QoreValue takeMember(QoreObject& obj, ExceptionSink* xsink, const char* mem, bool check_access = true) {
638  return obj.priv->takeMember(xsink, mem, check_access);
639  }
640 
641  DLLLOCAL static QoreValue takeMember(QoreObject& obj, LValueHelper& lvh, const char* mem) {
642  return obj.priv->takeMember(lvh, mem);
643  }
644 
645  DLLLOCAL static void takeMembers(QoreObject& o, QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l) {
646  o.priv->takeMembers(rv, lvh, l);
647  }
648 
649  DLLLOCAL static int getLValue(const QoreObject& obj, const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink) {
650  return obj.priv->getLValue(key, lvh, class_ctx, for_remove, xsink);
651  }
652 
653  DLLLOCAL static QoreStringNode* firstKey(QoreObject* obj, ExceptionSink* xsink) {
654  return obj->priv->firstKey(xsink);
655  }
656 
657  DLLLOCAL static QoreStringNode* lastKey(QoreObject* obj, ExceptionSink* xsink) {
658  return obj->priv->lastKey(xsink);
659  }
660 
661  DLLLOCAL static unsigned getScanCount(const QoreObject& o) {
662  return o.priv->getScanCount();
663  }
664 
665  DLLLOCAL static void incScanCount(const QoreObject& o, int dt) {
666  o.priv->incScanCount(dt);
667  }
668 };
669 
670 class qore_object_lock_handoff_helper {
671 private:
672  qore_object_private* pobj;
673  AutoVLock& vl;
674 
675 public:
676  DLLLOCAL qore_object_lock_handoff_helper(qore_object_private* n_pobj, AutoVLock& n_vl) : pobj(n_pobj), vl(n_vl) {
677  if (pobj->obj == vl.getObject()) {
678  assert(vl.getRWL() == &pobj->rml);
679  vl.clear();
680  return;
681  }
682 
683  // reference current object
684  pobj->obj->tRef();
685 
686  // unlock previous lock and release from AutoVLock structure
687  vl.del();
688 
689  // lock current object
690  pobj->rml.wrlock();
691  }
692 
693  DLLLOCAL ~qore_object_lock_handoff_helper() {
694  // unlock if lock not saved in AutoVLock structure
695  if (pobj) {
696  //printd(5, "Object lock %p unlocked (handoff)\n", &pobj->rml);
697  pobj->rml.unlock();
698  pobj->obj->tDeref();
699  }
700  }
701 
702  DLLLOCAL void stayLocked() {
703  vl.set(pobj->obj, &pobj->rml);
704  pobj = nullptr;
705  }
706 };
707 
708 #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 QoreVarRWLock * getRWL() const
gets the current read-write lock
DLLLOCAL QoreObject * getObject() const
gets the current object
DLLLOCAL void set(QoreVarRWLock *n_rwl)
sets the current lock
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:577
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
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:249
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 * getLastKey() const
returns the cstring value of the last key in the hash
DLLEXPORT const char * getFirstKey() const
returns the cstring value of the first 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:135
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:127
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:654
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:275