Qore Programming Language  0.9.16
QoreObjectIntern.h
1 /* -*- mode: c++; indent-tabs-mode: nil -*- */
2 /*
3  QoreObjectIntern.h
4 
5  Qore Programming Language
6 
7  Copyright (C) 2003 - 2020 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, delete_blocker_run, 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, const qore_class_private*& member_class_ctx) const {
348  assert(!member_class_ctx);
349 
350  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
351  const QoreMemberInfo* info = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
352  if (!info) {
353  return theclass->runtimeHasPublicMembersInHierarchy() ? QOA_PUB_ERROR : QOA_OK;
354  }
355  member_class_ctx = info->getClassContext(class_ctx);
356  return ((info->access > Public) && !class_ctx) ? QOA_PRIV_ERROR : QOA_OK;
357  }
358 
359  DLLLOCAL int checkMemberAccess(const char* mem, const qore_class_private* class_ctx, const qore_class_private*& member_class_ctx, ExceptionSink* xsink) const {
360  int rc = checkMemberAccess(mem, class_ctx, member_class_ctx);
361  if (!rc) {
362  return 0;
363  }
364 
365  if (rc == QOA_PRIV_ERROR) {
366  doPrivateException(mem, xsink);
367  } else {
368  doPublicException(mem, xsink);
369  }
370  return -1;
371  }
372 
373  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 {
374  assert(!member_class_ctx);
375  const qore_class_private* theclass_priv = qore_class_private::get(*theclass);
376  const QoreMemberInfo* mi = theclass_priv->runtimeGetMemberInfo(mem, class_ctx);
377  if (mi) {
378  if (mi->access > Public && !class_ctx) {
379  doPrivateException(mem, xsink);
380  return -1;
381  }
382 
383  member_class_ctx = mi->getClassContext(class_ctx);
384  typeInfo = mi->getTypeInfo();
385  return 0;
386  }
387 
388  // member is not declared
389  if (theclass->runtimeHasPublicMembersInHierarchy()) {
390  doPublicException(mem, xsink);
391  return -1;
392  }
393  return 0;
394  }
395 
396  DLLLOCAL QoreValue takeMember(ExceptionSink* xsink, const char* mem, bool check_access = true);
397 
398  DLLLOCAL QoreValue takeMember(LValueHelper& lvh, const char* mem);
399 
400  DLLLOCAL void takeMembers(QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l);
401 
402  DLLLOCAL QoreValue getReferencedMemberNoMethod(const char* mem, ExceptionSink* xsink) const;
403 
404  // lock not held on entry
405  DLLLOCAL void doDeleteIntern(ExceptionSink* xsink) {
406  printd(5, "qore_object_private::doDeleteIntern() execing destructor() obj: %p\n", obj);
407 
408  // increment reference count temporarily for destructor
409  {
410  AutoLocker slr(rlck);
411  ++obj->references;
412  }
413 
414  theclass->execDestructor(obj, xsink);
415 
416  cdmap_t* cdm;
417  QoreHashNode* td;
418  {
419  QoreAutoVarRWWriteLocker al(rml);
420  assert(status != OS_DELETED);
421  assert(data);
422  status = OS_DELETED;
423 
424  cdm = cdmap;
425  cdmap = nullptr;
426 
427  td = data;
428  data = nullptr;
429 
430  removeInvalidateRSetIntern();
431  }
432 
433  cleanup(xsink, td, cdm);
434 
435  obj->deref(xsink);
436  }
437 
438  DLLLOCAL void cleanup(ExceptionSink* xsink, QoreHashNode* td, cdmap_t* cdm) {
439  if (privateData) {
440  printd(5, "qore_object_private::cleanup() this: %p privateData: %p\n", this, privateData);
441  delete privateData;
442 #ifdef DEBUG
443  privateData = nullptr;
444 #endif
445  }
446 
447  td->clear(xsink, true);
448  td->deref(xsink);
449 
450  if (cdm) {
451  for (auto& i : *cdm) {
452  i.second->clear(xsink, true);
453  i.second->deref(xsink);
454  }
455  delete cdm;
456  }
457  }
458 
459  // this method is called when there is an exception in a constructor and the object should be deleted
460  DLLLOCAL void obliterate(ExceptionSink* xsink) {
461  printd(5, "qore_object_private::obliterate() obj: %p class: %s %d->%d\n", obj, theclass->getName(), obj->references.load(), obj->references.load() - 1);
462 
463 #ifdef QORE_DEBUG_OBJ_REFS
464  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);
465 #endif
466 
467  {
468  AutoLocker slr(rlck);
469  if (--obj->references)
470  return;
471  }
472 
473  {
474  QoreSafeVarRWWriteLocker sl(rml);
475 
476  if (in_destructor || status != OS_OK) {
477  printd(5, "qore_object_private::obliterate() obj: %p data: %p in_destructor: %d status: %d\n", obj, data, in_destructor, status);
478  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
479  sl.unlock();
480  tDeref();
481  return;
482  }
483 
484  //printd(5, "Object lock %p locked (safe)\n", &rml);
485  printd(5, "qore_object_private::obliterate() obj: %p class: %s\n", obj, theclass->getName());
486 
487  status = OS_DELETED;
488  cdmap_t* cdm = cdmap;
489  cdmap = nullptr;
490  QoreHashNode* td = data;
491  data = nullptr;
492 
493  removeInvalidateRSetIntern();
494 
495  //printd(5, "Object lock %p unlocked (safe)\n", &rml);
496  sl.unlock();
497 
498  if (privateData)
499  privateData->derefAll(xsink);
500 
501  cleanup(xsink, td, cdm);
502  }
503  tDeref();
504  }
505 
506  DLLLOCAL void doPrivateException(const char* mem, ExceptionSink* xsink) const {
507  xsink->raiseException("PRIVATE-MEMBER", "'%s' is a private member of class '%s'", mem, theclass->getName());
508  }
509 
510  DLLLOCAL void doPublicException(const char* mem, ExceptionSink* xsink) const {
511  xsink->raiseException("INVALID-MEMBER", "'%s' is not a registered member of class '%s'", mem, theclass->getName());
512  }
513 
514  DLLLOCAL virtual const char* getName() const {
515  return theclass->getName();
516  }
517 
518  DLLLOCAL virtual void deleteObject() {
519  delete obj;
520  }
521 
522  DLLLOCAL virtual bool isValidImpl() const {
523  if (status != OS_OK || in_destructor) {
524  printd(QRO_LVL, "qore_object_intern::isValidImpl() this: %p cannot delete graph obj status: %d in_destructor: %d\n", this, status, in_destructor);
525  return false;
526  }
527  return true;
528  }
529 
530  DLLLOCAL virtual bool scanMembersIntern(RSetHelper& rsh, QoreHashNode* odata);
531 
532  DLLLOCAL virtual bool scanMembers(RSetHelper& rsh);
533 
534  // always called in the rsection lock
535  DLLLOCAL virtual bool needsScan(bool scan_now) {
536  assert(rml.hasRSectionLock());
537  printd(5, "qore_object_private::needsScan() scan_count: %d scan_private_data: %d scan_now: %d\n",
538  getScanCount(), scan_private_data, scan_now);
539 
540  // the status cannot change while this lock is held
541  if ((!getScanCount() && !scan_private_data) || status != OS_OK) {
542  return false;
543  }
544 
545  {
546  AutoLocker al(rlck);
547  if (deferred_scan) {
548  if (!rrefs && scan_now) {
549  deferred_scan = false;
550  return true;
551  }
552  return false;
553  }
554  if (!rrefs) {
555  return true;
556  }
557  deferred_scan = true;
558  // if there is no rset, our job is done
559  if (!rset && !scan_private_data) {
560  return false;
561  }
562  // if we have an rset, then we need to invalidate it and ensure that
563  // rrefs does not go to zero until this is done
564  rref_wait = true;
565  }
566 
567  removeInvalidateRSetIntern();
568  AutoLocker al(rlck);
569  rref_wait = false;
570  if (rref_waiting) {
571  rcond.broadcast();
572  }
573 
574  return false;
575  }
576 
577  DLLLOCAL void mergeDataToHash(QoreHashNode* hash, SafeDerefHelper& sdh, ExceptionSink* xsink) const;
578 
579  DLLLOCAL void setPrivate(qore_classid_t key, AbstractPrivateData* pd) {
580  if (!privateData) {
581  privateData = new KeyList;
582  }
583  printd(5, "qore_object_private::setPrivate() this: %p 2:privateData: %p (%s) key: %d pd: %p\n", this, privateData, theclass->getName(), key, pd);
584  privateData->insert(key, pd);
585  addVirtualPrivateData(key, pd);
586  }
587 
588  // add virtual IDs for private data to class list
589  DLLLOCAL void addVirtualPrivateData(qore_classid_t key, AbstractPrivateData* apd) {
590  // first get parent class corresponding to "key"
591  QoreClass* qc = theclass->getClass(key);
592 
593  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p privateData: %p key: %d apd: %p qc: %p '%s'\n", this, privateData, key, apd, qc, qc->getName());
594  assert(qc);
595  BCSMList* sml = qc->getBCSMList();
596  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p qc: %p '%s' sml: %p\n", this, qc, qc->getName(), sml);
597  if (!sml)
598  return;
599 
600  for (class_list_t::const_iterator i = sml->begin(), e = sml->end(); i != e; ++i) {
601  //printd(5, "qore_object_private::addVirtualPrivateData() this: %p i: %p '%s' key: %d virt: %s\n", this, i->first, i->first->getName(), i->first->getID(), i->second ? "true" : "false");
602  if (i->second)
603  privateData->insertVirtual(i->first->getID(), apd);
604  }
605  }
606 
607  DLLLOCAL AbstractPrivateData* getAndRemovePrivateData(qore_classid_t key, ExceptionSink* xsink) {
608  QoreSafeVarRWWriteLocker sl(rml);
609  return privateData ? privateData->getAndRemovePtr(key) : nullptr;
610  }
611 
612  DLLLOCAL AbstractPrivateData* getReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
613 
614  DLLLOCAL AbstractPrivateData* tryGetReferencedPrivateData(qore_classid_t key, ExceptionSink* xsink) const;
615 
616  DLLLOCAL QoreValue evalBuiltinMethodWithPrivateData(const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink);
617 
618  // no locking necessary; if class_ctx is non-null, an internal member is being initialized
619  DLLLOCAL QoreValue& getMemberValueRefForInitialization(const char* member, const qore_class_private* class_ctx);
620 
622 
626  DLLLOCAL QoreHashNode* getRuntimeMemberHash(ExceptionSink* xsink) const;
627 
628  DLLLOCAL void incScanCount(int dt) {
629  assert(dt);
630  assert(obj_count || dt > 0);
631  //printd(5, "qore_object_private::incScanCount() this: %p dt: %d: %d -> %d\n", this, dt, obj_count, obj_count + dt);
632  obj_count += dt;
633  }
634 
635  DLLLOCAL unsigned getScanCount() const {
636  return obj_count;
637  }
638 
639  DLLLOCAL VRMutex* getGate() const {
640  return &gate;
641  }
642 
643  /*
644  DLLLOCAL static bool hackId(const QoreObject& obj) {
645  if (!obj.priv->data)
646  return false;
647  const AbstractQoreNode* n = obj.priv->data->getKeyValue("name");
648  if (n && n->getType() == NT_STRING && strstr(reinterpret_cast<const QoreStringNode*>(n)->getBuffer(), "http-test"))
649  return true;
650  return false;
651  }
652  */
653 
654  // custom reference handler - unlocked
657  DLLLOCAL void customRefIntern(bool real);
658 
659  // custom dereference handler - unlocked
662  DLLLOCAL void customDeref(bool real, ExceptionSink* xsink);
663 
664  DLLLOCAL int startCall(const char* mname, ExceptionSink* xsink);
665 
666  DLLLOCAL void endCall(ExceptionSink* xsink);
667 
668  // increments the real reference count without incrementing the actual reference count
669  // (i.e. turns the current not real reference into a "real" reference; one that cannot
670  // participate in recursive graphs)
671  DLLLOCAL void setRealReference();
672 
673  // decrements the real reference count without decrementing the actual reference count
674  DLLLOCAL void unsetRealReference();
675 
676  DLLLOCAL const char* getClassName() const {
677  return theclass->getName();
678  }
679 
680  DLLLOCAL static QoreValue evalBuiltinMethodWithPrivateData(QoreObject& obj, const QoreMethod& method, const BuiltinNormalMethodVariantBase* meth, const QoreListNode* args, q_rt_flags_t rtflags, ExceptionSink* xsink) {
681  return obj.priv->evalBuiltinMethodWithPrivateData(method, meth, args, rtflags, xsink);
682  }
683 
684  DLLLOCAL static qore_object_private* get(QoreObject& obj) {
685  return obj.priv;
686  }
687 
688  DLLLOCAL static const qore_object_private* get(const QoreObject& obj) {
689  return obj.priv;
690  }
691 
692  DLLLOCAL static QoreValue takeMember(QoreObject& obj, ExceptionSink* xsink, const char* mem, bool check_access = true) {
693  return obj.priv->takeMember(xsink, mem, check_access);
694  }
695 
696  DLLLOCAL static QoreValue takeMember(QoreObject& obj, LValueHelper& lvh, const char* mem) {
697  return obj.priv->takeMember(lvh, mem);
698  }
699 
700  DLLLOCAL static void takeMembers(QoreObject& o, QoreLValueGeneric& rv, LValueHelper& lvh, const QoreListNode* l) {
701  o.priv->takeMembers(rv, lvh, l);
702  }
703 
704  DLLLOCAL static int getLValue(const QoreObject& obj, const char* key, LValueHelper& lvh, const qore_class_private* class_ctx, bool for_remove, ExceptionSink* xsink) {
705  return obj.priv->getLValue(key, lvh, class_ctx, for_remove, xsink);
706  }
707 
708  DLLLOCAL static QoreStringNode* firstKey(QoreObject* obj, ExceptionSink* xsink) {
709  return obj->priv->firstKey(xsink);
710  }
711 
712  DLLLOCAL static QoreStringNode* lastKey(QoreObject* obj, ExceptionSink* xsink) {
713  return obj->priv->lastKey(xsink);
714  }
715 
716  DLLLOCAL static unsigned getScanCount(const QoreObject& o) {
717  return o.priv->getScanCount();
718  }
719 
720  DLLLOCAL static void incScanCount(const QoreObject& o, int dt) {
721  o.priv->incScanCount(dt);
722  }
723 };
724 
725 class qore_object_lock_handoff_helper {
726 private:
727  qore_object_private* pobj;
728  AutoVLock& vl;
729 
730 public:
731  DLLLOCAL qore_object_lock_handoff_helper(qore_object_private* n_pobj, AutoVLock& n_vl) : pobj(n_pobj), vl(n_vl) {
732  if (pobj->obj == vl.getObject()) {
733  assert(vl.getRWL() == &pobj->rml);
734  vl.clear();
735  return;
736  }
737 
738  // reference current object
739  pobj->obj->tRef();
740 
741  // unlock previous lock and release from AutoVLock structure
742  vl.del();
743 
744  // lock current object
745  pobj->rml.wrlock();
746  }
747 
748  DLLLOCAL ~qore_object_lock_handoff_helper() {
749  // unlock if lock not saved in AutoVLock structure
750  if (pobj) {
751  //printd(5, "Object lock %p unlocked (handoff)\n", &pobj->rml);
752  pobj->rml.unlock();
753  pobj->obj->tDeref();
754  }
755  }
756 
757  DLLLOCAL void stayLocked() {
758  vl.set(pobj->obj, &pobj->rml);
759  pobj = nullptr;
760  }
761 };
762 
763 #endif
q_rt_flags_t
uint64_t q_rt_flags_t
runtime code execution flags
Definition: common.h:263
AutoVLock::set
DLLLOCAL void set(QoreVarRWLock *n_rwl)
sets the current lock
NT_OBJECT
const qore_type_t NT_OBJECT
type value for QoreObject
Definition: node_types.h:52
QoreHashNode::getFirstKey
const DLLEXPORT char * getFirstKey() const
returns the cstring value of the first key in the hash
QoreProgram
supports parsing and executing Qore-language code, reference counted, dynamically-allocated only
Definition: QoreProgram.h:126
QoreValue
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:262
ReverseConstHashIterator
reverse constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:640
SafeDerefHelper
Helps dereference values outside of locks.
Definition: QoreLibIntern.h:462
QoreHashNode
This is the hash or associative list container type in Qore, dynamically allocated only,...
Definition: QoreHashNode.h:50
QoreClass::getClass
DLLEXPORT QoreClass * getClass(qore_classid_t cid) const
returns a pointer to the QoreClass object representing the class ID passed if it exists in the class ...
QoreClass
defines a Qore-language class
Definition: QoreClass.h:239
QoreClass::getName
const DLLEXPORT char * getName() const
returns the class name
AbstractPrivateData::ref
DLLLOCAL void ref()
increments the reference count of the object
Definition: AbstractPrivateData.h:53
AbstractQoreNode::getType
DLLLOCAL qore_type_t getType() const
returns the data type
Definition: AbstractQoreNode.h:172
QoreListNode
This is the list container type in Qore, dynamically allocated only, reference counted.
Definition: QoreListNode.h:52
AutoVLock::clear
DLLLOCAL void clear()
leaves the lock locked and the object referenced and clears the object and lock pointers
ConstHashIterator
constant iterator class for QoreHashNode, to be only created on the stack
Definition: QoreHashNode.h:563
QoreString::sprintf
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
AutoLocker
provides a safe and exception-safe way to hold locks in Qore, only to be used on the stack,...
Definition: QoreThreadLock.h:136
QoreString
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:81
ExceptionSink::raiseException
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
AutoVLock::del
DLLEXPORT void del()
manually releases the lock currently held
AutoVLock::getRWL
DLLLOCAL QoreVarRWLock * getRWL() const
gets the current read-write lock
QoreObject
the implementation of Qore's object data type, reference counted, dynamically-allocated only
Definition: QoreObject.h:61
ExceptionSink
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:48
AutoVLock::getObject
DLLLOCAL QoreObject * getObject() const
gets the current object
qore_classid_t
unsigned qore_classid_t
used for the unique class ID for QoreClass objects
Definition: common.h:79
AbstractQoreNode::deref
DLLEXPORT void deref(ExceptionSink *xsink)
decrements the reference count and calls derefImpl() if there_can_be_only_one is false,...
QoreMethod
a method in a QoreClass
Definition: QoreClass.h:125
AbstractPrivateData
the base class for all data to be used as private data of Qore objects
Definition: AbstractPrivateData.h:44
NT_HASH
const qore_type_t NT_HASH
type value for QoreHashNode
Definition: node_types.h:51
QoreHashNode::getLastKey
const DLLEXPORT char * getLastKey() const
returns the cstring value of the last key in the hash
QoreStringNode
Qore's string value type, reference counted, dynamically-allocated only.
Definition: QoreStringNode.h:50
AbstractQoreNode
The base class for all value and parse types in Qore expression trees.
Definition: AbstractQoreNode.h:54
AutoVLock
AutoVLock is a container for safely managing global variable and object lock handovers,...
Definition: AutoVLock.h:80