1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_MEM_HEAP_H 17 #define ECMASCRIPT_MEM_HEAP_H 18 19 #include "ecmascript/base/config.h" 20 #include "ecmascript/frames.h" 21 #include "ecmascript/js_thread.h" 22 #include "ecmascript/mem/linear_space.h" 23 #include "ecmascript/mem/mark_stack.h" 24 #include "ecmascript/mem/sparse_space.h" 25 #include "ecmascript/mem/work_manager.h" 26 #include "ecmascript/taskpool/taskpool.h" 27 28 namespace panda::ecmascript { 29 class ConcurrentMarker; 30 class ConcurrentSweeper; 31 class EcmaVM; 32 class FullGC; 33 class HeapRegionAllocator; 34 class HeapTracker; 35 class Marker; 36 class MemController; 37 class NativeAreaAllocator; 38 class ParallelEvacuator; 39 class PartialGC; 40 class STWYoungGC; 41 class JSNativePointer; 42 43 enum class MarkType : uint8_t { 44 MARK_YOUNG, 45 MARK_FULL 46 }; 47 48 enum class MemGrowingType : uint8_t { 49 HIGH_THROUGHPUT, 50 CONSERVATIVE, 51 PRESSURE 52 }; 53 54 enum class IdleHeapSizePtr : uint8_t { 55 IDLE_HEAP_SIZE_1 = 0, 56 IDLE_HEAP_SIZE_2, 57 IDLE_HEAP_SIZE_3 58 }; 59 60 struct IdleData { 61 int64_t idleHeapObjectSize1 {0}; 62 int64_t idleHeapObjectSize2 {0}; 63 int64_t idleHeapObjectSize3 {0}; 64 IdleHeapSizePtr curPtr_ {IdleHeapSizePtr::IDLE_HEAP_SIZE_1}; 65 66 static constexpr int64_t REST_HEAP_GROWTH_LIMIT = 200_KB; CheckIsRestIdleData67 bool CheckIsRest() 68 { 69 if (abs(idleHeapObjectSize1 - idleHeapObjectSize2) < REST_HEAP_GROWTH_LIMIT && 70 abs(idleHeapObjectSize2 - idleHeapObjectSize3) < REST_HEAP_GROWTH_LIMIT) { 71 return true; 72 } 73 return false; 74 } 75 SetNextValueIdleData76 void SetNextValue(int64_t idleHeapObjectSize) 77 { 78 switch (curPtr_) { 79 case IdleHeapSizePtr::IDLE_HEAP_SIZE_1: 80 idleHeapObjectSize1 = idleHeapObjectSize; 81 curPtr_ = IdleHeapSizePtr::IDLE_HEAP_SIZE_2; 82 break; 83 case IdleHeapSizePtr::IDLE_HEAP_SIZE_2: 84 idleHeapObjectSize2 = idleHeapObjectSize; 85 curPtr_ = IdleHeapSizePtr::IDLE_HEAP_SIZE_3; 86 break; 87 case IdleHeapSizePtr::IDLE_HEAP_SIZE_3: 88 idleHeapObjectSize3 = idleHeapObjectSize; 89 curPtr_ = IdleHeapSizePtr::IDLE_HEAP_SIZE_1; 90 break; 91 default: 92 LOG_ECMA(FATAL) << "this branch is unreachable"; 93 UNREACHABLE(); 94 } 95 } 96 }; 97 98 enum class HeapMode { 99 NORMAL, 100 SPAWN, 101 SHARE, 102 }; 103 104 class Heap { 105 public: 106 explicit Heap(EcmaVM *ecmaVm); 107 ~Heap() = default; 108 NO_COPY_SEMANTIC(Heap); 109 NO_MOVE_SEMANTIC(Heap); 110 void Initialize(); 111 void Destroy(); 112 void Prepare(); 113 void Resume(TriggerGCType gcType); 114 void ResumeForAppSpawn(); 115 void CompactHeapBeforeFork(); 116 void DisableParallelGC(); 117 void EnableParallelGC(); 118 // fixme: Rename NewSpace to YoungSpace. 119 // This is the active young generation space that the new objects are allocated in 120 // or copied into (from the other semi space) during semi space GC. GetNewSpace()121 SemiSpace *GetNewSpace() const 122 { 123 return activeSemiSpace_; 124 } 125 126 /* 127 * Return the original active space where the objects are to be evacuated during semi space GC. 128 * This should be invoked only in the evacuation phase of semi space GC. 129 * fixme: Get rid of this interface or make it safe considering the above implicit limitation / requirement. 130 */ GetFromSpaceDuringEvacuation()131 SemiSpace *GetFromSpaceDuringEvacuation() const 132 { 133 return inactiveSemiSpace_; 134 } 135 GetOldSpace()136 OldSpace *GetOldSpace() const 137 { 138 return oldSpace_; 139 } 140 GetNonMovableSpace()141 NonMovableSpace *GetNonMovableSpace() const 142 { 143 return nonMovableSpace_; 144 } 145 GetHugeObjectSpace()146 HugeObjectSpace *GetHugeObjectSpace() const 147 { 148 return hugeObjectSpace_; 149 } 150 GetMachineCodeSpace()151 MachineCodeSpace *GetMachineCodeSpace() const 152 { 153 return machineCodeSpace_; 154 } 155 GetSnapshotSpace()156 SnapshotSpace *GetSnapshotSpace() const 157 { 158 return snapshotSpace_; 159 } 160 GetReadOnlySpace()161 ReadOnlySpace *GetReadOnlySpace() const 162 { 163 return readOnlySpace_; 164 } 165 GetAppSpawnSpace()166 AppSpawnSpace *GetAppSpawnSpace() const 167 { 168 return appSpawnSpace_; 169 } 170 GetSpaceWithType(MemSpaceType type)171 SparseSpace *GetSpaceWithType(MemSpaceType type) const 172 { 173 switch (type) { 174 case MemSpaceType::OLD_SPACE: 175 return oldSpace_; 176 break; 177 case MemSpaceType::NON_MOVABLE: 178 return nonMovableSpace_; 179 break; 180 case MemSpaceType::MACHINE_CODE_SPACE: 181 return machineCodeSpace_; 182 break; 183 default: 184 UNREACHABLE(); 185 break; 186 } 187 } 188 GetSTWYoungGC()189 STWYoungGC *GetSTWYoungGC() const 190 { 191 return stwYoungGC_; 192 } 193 GetPartialGC()194 PartialGC *GetPartialGC() const 195 { 196 return partialGC_; 197 } 198 GetFullGC()199 FullGC *GetFullGC() const 200 { 201 return fullGC_; 202 } 203 GetSweeper()204 ConcurrentSweeper *GetSweeper() const 205 { 206 return sweeper_; 207 } 208 GetEvacuator()209 ParallelEvacuator *GetEvacuator() const 210 { 211 return evacuator_; 212 } 213 GetConcurrentMarker()214 ConcurrentMarker *GetConcurrentMarker() const 215 { 216 return concurrentMarker_; 217 } 218 GetNonMovableMarker()219 Marker *GetNonMovableMarker() const 220 { 221 return nonMovableMarker_; 222 } 223 GetSemiGCMarker()224 Marker *GetSemiGCMarker() const 225 { 226 return semiGCMarker_; 227 } 228 GetCompressGCMarker()229 Marker *GetCompressGCMarker() const 230 { 231 return compressGCMarker_; 232 } 233 GetEcmaVM()234 EcmaVM *GetEcmaVM() const 235 { 236 return ecmaVm_; 237 } 238 GetJSThread()239 JSThread *GetJSThread() const 240 { 241 return thread_; 242 } 243 GetWorkManager()244 WorkManager *GetWorkManager() const 245 { 246 return workManager_; 247 } 248 GetMemController()249 MemController *GetMemController() const 250 { 251 return memController_; 252 } 253 254 /* 255 * For object allocations. 256 */ 257 258 // Young 259 inline TaggedObject *AllocateYoungOrHugeObject(JSHClass *hclass); 260 inline TaggedObject *AllocateYoungOrHugeObject(JSHClass *hclass, size_t size); 261 inline TaggedObject *AllocateReadOnlyOrHugeObject(JSHClass *hclass); 262 inline TaggedObject *AllocateReadOnlyOrHugeObject(JSHClass *hclass, size_t size); 263 inline TaggedObject *AllocateYoungOrHugeObject(size_t size); 264 inline uintptr_t AllocateYoungSync(size_t size); 265 inline TaggedObject *TryAllocateYoungGeneration(JSHClass *hclass, size_t size); 266 // Old 267 inline TaggedObject *AllocateOldOrHugeObject(JSHClass *hclass); 268 inline TaggedObject *AllocateOldOrHugeObject(JSHClass *hclass, size_t size); 269 // Non-movable 270 inline TaggedObject *AllocateNonMovableOrHugeObject(JSHClass *hclass); 271 inline TaggedObject *AllocateNonMovableOrHugeObject(JSHClass *hclass, size_t size); 272 inline TaggedObject *AllocateClassClass(JSHClass *hclass, size_t size); 273 // Huge 274 inline TaggedObject *AllocateHugeObject(JSHClass *hclass, size_t size); 275 inline TaggedObject *AllocateHugeObject(size_t size); 276 // Machine code 277 inline TaggedObject *AllocateMachineCodeObject(JSHClass *hclass, size_t size); 278 // Snapshot 279 inline uintptr_t AllocateSnapshotSpace(size_t size); 280 GetNativeAreaAllocator()281 NativeAreaAllocator *GetNativeAreaAllocator() const 282 { 283 return nativeAreaAllocator_; 284 } 285 GetHeapRegionAllocator()286 HeapRegionAllocator *GetHeapRegionAllocator() const 287 { 288 return heapRegionAllocator_; 289 } 290 291 /* 292 * GC triggers. 293 */ 294 295 void CollectGarbage(TriggerGCType gcType); 296 297 void CheckAndTriggerOldGC(size_t size = 0); 298 299 /* 300 * Parallel GC related configurations and utilities. 301 */ 302 303 void PostParallelGCTask(ParallelGCTaskPhase taskPhase); 304 IsParallelGCEnabled()305 bool IsParallelGCEnabled() const 306 { 307 return parallelGC_; 308 } 309 void ChangeGCParams(bool inBackground); 310 void TriggerIdleCollection(int idleMicroSec); 311 void NotifyMemoryPressure(bool inHighMemoryPressure); 312 bool CheckCanDistributeTask(); 313 314 void WaitRunningTaskFinished(); 315 316 void TryTriggerConcurrentMarking(); 317 void AdjustBySurvivalRate(size_t originalNewSpaceSize); 318 void TriggerConcurrentMarking(); 319 320 /* 321 * Wait for existing concurrent marking tasks to be finished (if any). 322 * Return true if there's ongoing concurrent marking. 323 */ 324 bool CheckOngoingConcurrentMarking(); 325 326 /* 327 * Functions invoked during GC. 328 */ 329 SetMarkType(MarkType markType)330 void SetMarkType(MarkType markType) 331 { 332 markType_ = markType; 333 } 334 IsFullMark()335 bool IsFullMark() const 336 { 337 return markType_ == MarkType::MARK_FULL; 338 } 339 340 inline void SwapNewSpace(); 341 inline void SwapOldSpace(); 342 343 inline bool MoveYoungRegionSync(Region *region); 344 inline void MergeToOldSpaceSync(LocalSpace *localSpace); 345 346 template<class Callback> 347 void EnumerateOldSpaceRegions(const Callback &cb, Region *region = nullptr) const; 348 349 template<class Callback> 350 void EnumerateNonNewSpaceRegions(const Callback &cb) const; 351 352 template<class Callback> 353 void EnumerateNonNewSpaceRegionsWithRecord(const Callback &cb) const; 354 355 template<class Callback> 356 void EnumerateNewSpaceRegions(const Callback &cb) const; 357 358 template<class Callback> 359 void EnumerateSnapshotSpaceRegions(const Callback &cb) const; 360 361 template<class Callback> 362 void EnumerateNonMovableRegions(const Callback &cb) const; 363 364 template<class Callback> 365 inline void EnumerateRegions(const Callback &cb) const; 366 367 inline void ClearSlotsRange(Region *current, uintptr_t freeStart, uintptr_t freeEnd); 368 369 void WaitAllTasksFinished(); 370 void WaitConcurrentMarkingFinished(); 371 GetMemGrowingType()372 MemGrowingType GetMemGrowingType() const 373 { 374 return memGrowingtype_; 375 } 376 SetMemGrowingType(MemGrowingType memGrowingType)377 void SetMemGrowingType(MemGrowingType memGrowingType) 378 { 379 memGrowingtype_ = memGrowingType; 380 } 381 382 inline size_t GetCommittedSize() const; 383 384 inline size_t GetHeapObjectSize() const; 385 386 inline int32_t GetHeapObjectCount() const; 387 GetPromotedSize()388 size_t GetPromotedSize() const 389 { 390 return promotedSize_; 391 } 392 393 size_t GetArrayBufferSize() const; 394 GetMaxMarkTaskCount()395 uint32_t GetMaxMarkTaskCount() const 396 { 397 return maxMarkTaskCount_; 398 } 399 GetMaxEvacuateTaskCount()400 uint32_t GetMaxEvacuateTaskCount() const 401 { 402 return maxEvacuateTaskCount_; 403 } 404 405 /* 406 * Heap tracking will be used by tools like heap profiler etc. 407 */ 408 StartHeapTracking(HeapTracker * tracker)409 void StartHeapTracking(HeapTracker *tracker) 410 { 411 WaitAllTasksFinished(); 412 parallelGC_ = false; 413 tracker_ = tracker; 414 } 415 StopHeapTracking()416 void StopHeapTracking() 417 { 418 WaitAllTasksFinished(); 419 parallelGC_ = true; 420 tracker_ = nullptr; 421 } 422 423 inline void OnAllocateEvent(TaggedObject* address, size_t size); 424 inline void OnMoveEvent(uintptr_t address, TaggedObject* forwardAddress, size_t size); 425 void AddToKeptObjects(JSHandle<JSTaggedValue> value) const; 426 void ClearKeptObjects() const; 427 /* 428 * Funtions used by heap verification. 429 */ 430 431 template<class Callback> 432 void IterateOverObjects(const Callback &cb) const; 433 434 bool IsAlive(TaggedObject *object) const; 435 bool ContainObject(TaggedObject *object) const; 436 437 size_t VerifyHeapObjects() const; 438 size_t VerifyOldToNewRSet() const; 439 void StatisticHeapObject(TriggerGCType gcType) const; 440 void PrintHeapInfo(TriggerGCType gcType) const; 441 OldSpaceExceedCapacity(size_t size)442 bool OldSpaceExceedCapacity(size_t size) const 443 { 444 size_t totalSize = oldSpace_->GetCommittedSize() + hugeObjectSpace_->GetCommittedSize() + size; 445 return totalSize >= oldSpace_->GetMaximumCapacity() + oldSpace_->GetOutOfMemoryOvershootSize(); 446 } 447 OldSpaceExceedLimit()448 bool OldSpaceExceedLimit() const 449 { 450 size_t totalSize = oldSpace_->GetHeapObjectSize() + hugeObjectSpace_->GetHeapObjectSize(); 451 return totalSize >= oldSpace_->GetInitialCapacity(); 452 } 453 454 void AdjustSpaceSizeForAppSpawn(); 455 #if ECMASCRIPT_ENABLE_HEAP_VERIFY IsVerifying()456 bool IsVerifying() const 457 { 458 return isVerifying_; 459 } 460 #endif ShouldMoveToRoSpace(JSHClass * hclass,TaggedObject * object)461 static bool ShouldMoveToRoSpace(JSHClass *hclass, TaggedObject *object) 462 { 463 return hclass->IsString() && !Region::ObjectAddressToRange(object)->InHugeObjectSpace(); 464 } 465 IsFullMarkRequested()466 bool IsFullMarkRequested() const 467 { 468 return fullMarkRequested_; 469 } 470 SetFullMarkRequestedState(bool fullMarkRequested)471 void SetFullMarkRequestedState(bool fullMarkRequested) 472 { 473 fullMarkRequested_ = fullMarkRequested; 474 } 475 ShouldThrowOOMError(bool shouldThrow)476 void ShouldThrowOOMError(bool shouldThrow) 477 { 478 shouldThrowOOMError_ = shouldThrow; 479 } 480 SetHeapMode(HeapMode mode)481 void SetHeapMode(HeapMode mode) 482 { 483 mode_ = mode; 484 } 485 486 void ThrowOutOfMemoryError(size_t size, std::string functionName); 487 488 void IncreaseNativeBindingSize(bool nonMovable, size_t size); 489 void IncreaseNativeBindingSize(JSNativePointer *object); ResetNativeBindingSize()490 void ResetNativeBindingSize() 491 { 492 activeSemiSpace_->ResetNativeBindingSize(); 493 nonNewSpaceNativeBindingSize_ = 0; 494 } 495 GetNativeBindingSize()496 size_t GetNativeBindingSize() const 497 { 498 return activeSemiSpace_->GetNativeBindingSize() + nonNewSpaceNativeBindingSize_; 499 } 500 GetNonNewSpaceNativeBindingSize()501 size_t GetNonNewSpaceNativeBindingSize() const 502 { 503 return nonNewSpaceNativeBindingSize_; 504 } 505 private: 506 static constexpr int64_t WAIT_FOR_APP_START_UP = 200; 507 static constexpr int IDLE_TIME_REMARK = 10; 508 static constexpr int IDLE_TIME_LIMIT = 15; // if idle time over 15ms we can do something 509 static constexpr int MIN_OLD_GC_LIMIT = 10000; // 10s 510 static constexpr int REST_HEAP_GROWTH_LIMIT = 2_MB; 511 void FatalOutOfMemoryError(size_t size, std::string functionName); 512 void RecomputeLimits(); 513 void AdjustOldSpaceLimit(); 514 // record lastRegion for each space, which will be used in ReclaimRegions() 515 void PrepareRecordRegionsForReclaim(); 516 TriggerGCType SelectGCType() const; 517 void IncreaseTaskCount(); 518 void ReduceTaskCount(); 519 void WaitClearTaskFinished(); 520 void InvokeWeakNodeSecondPassCallback(); 521 inline void ReclaimRegions(TriggerGCType gcType); 522 523 class ParallelGCTask : public Task { 524 public: ParallelGCTask(int32_t id,Heap * heap,ParallelGCTaskPhase taskPhase)525 ParallelGCTask(int32_t id, Heap *heap, ParallelGCTaskPhase taskPhase) 526 : Task(id), heap_(heap), taskPhase_(taskPhase) {}; 527 ~ParallelGCTask() override = default; 528 bool Run(uint32_t threadIndex) override; 529 530 NO_COPY_SEMANTIC(ParallelGCTask); 531 NO_MOVE_SEMANTIC(ParallelGCTask); 532 533 private: 534 Heap *heap_ {nullptr}; 535 ParallelGCTaskPhase taskPhase_; 536 }; 537 538 class AsyncClearTask : public Task { 539 public: AsyncClearTask(int32_t id,Heap * heap,TriggerGCType type)540 AsyncClearTask(int32_t id, Heap *heap, TriggerGCType type) 541 : Task(id), heap_(heap), gcType_(type) {} 542 ~AsyncClearTask() override = default; 543 bool Run(uint32_t threadIndex) override; 544 545 NO_COPY_SEMANTIC(AsyncClearTask); 546 NO_MOVE_SEMANTIC(AsyncClearTask); 547 private: 548 Heap *heap_; 549 TriggerGCType gcType_; 550 }; 551 552 EcmaVM *ecmaVm_ {nullptr}; 553 JSThread *thread_ {nullptr}; 554 555 /* 556 * Heap spaces. 557 */ 558 559 /* 560 * Young generation spaces where most new objects are allocated. 561 * (only one of the spaces is active at a time in semi space GC). 562 */ 563 SemiSpace *activeSemiSpace_ {nullptr}; 564 SemiSpace *inactiveSemiSpace_ {nullptr}; 565 566 // Old generation spaces where some long living objects are allocated or promoted. 567 OldSpace *oldSpace_ {nullptr}; 568 OldSpace *compressSpace_ {nullptr}; 569 ReadOnlySpace *readOnlySpace_ {nullptr}; 570 AppSpawnSpace *appSpawnSpace_ {nullptr}; 571 // Spaces used for special kinds of objects. 572 NonMovableSpace *nonMovableSpace_ {nullptr}; 573 MachineCodeSpace *machineCodeSpace_ {nullptr}; 574 HugeObjectSpace *hugeObjectSpace_ {nullptr}; 575 SnapshotSpace *snapshotSpace_ {nullptr}; 576 577 /* 578 * Garbage collectors collecting garbage in different scopes. 579 */ 580 581 /* 582 * Semi sapce GC which collects garbage only in young spaces. 583 * This is however optional for now because the partial GC also covers its functionality. 584 */ 585 STWYoungGC *stwYoungGC_ {nullptr}; 586 587 /* 588 * The mostly used partial GC which collects garbage in young spaces, 589 * and part of old spaces if needed determined by GC heuristics. 590 */ 591 PartialGC *partialGC_ {nullptr}; 592 593 // Full collector which collects garbage in all valid heap spaces. 594 FullGC *fullGC_ {nullptr}; 595 596 // Concurrent marker which coordinates actions of GC markers and mutators. 597 ConcurrentMarker *concurrentMarker_ {nullptr}; 598 599 // Concurrent sweeper which coordinates actions of sweepers (in spaces excluding young semi spaces) and mutators. 600 ConcurrentSweeper *sweeper_ {nullptr}; 601 602 // Parallel evacuator which evacuates objects from one space to another one. 603 ParallelEvacuator *evacuator_ {nullptr}; 604 605 /* 606 * Different kinds of markers used by different collectors. 607 * Depending on the collector algorithm, some markers can do simple marking 608 * while some others need to handle object movement. 609 */ 610 Marker *nonMovableMarker_ {nullptr}; 611 Marker *semiGCMarker_ {nullptr}; 612 Marker *compressGCMarker_ {nullptr}; 613 614 // Work manager managing the tasks mostly generated in the GC mark phase. 615 WorkManager *workManager_ {nullptr}; 616 617 MarkType markType_ {MarkType::MARK_YOUNG}; 618 619 bool parallelGC_ {true}; 620 bool fullGCRequested_ {false}; 621 bool fullMarkRequested_ {false}; 622 bool oldSpaceLimitAdjusted_ {false}; 623 bool shouldThrowOOMError_ {false}; 624 bool runningSecondPassCallbacks_ {false}; 625 bool enableIdleGC_ {true}; 626 bool waitForStartUp_ {true}; 627 bool couldIdleGC_ {false}; 628 HeapMode mode_ { HeapMode::NORMAL }; 629 630 size_t globalSpaceAllocLimit_ {0}; 631 size_t promotedSize_ {0}; 632 size_t semiSpaceCopiedSize_ {0}; 633 size_t nonNewSpaceNativeBindingSize_{0}; 634 size_t globalSpaceNativeLimit_ {0}; 635 size_t idleHeapObjectSize_ {0}; 636 size_t idleOldSpace_ {16_MB}; 637 size_t triggerRestIdleSize_ {0}; 638 MemGrowingType memGrowingtype_ {MemGrowingType::HIGH_THROUGHPUT}; 639 640 bool clearTaskFinished_ {true}; 641 os::memory::Mutex waitClearTaskFinishedMutex_; 642 os::memory::ConditionVariable waitClearTaskFinishedCV_; 643 int64_t idleTime_ {0}; 644 uint32_t runningTaskCount_ {0}; 645 // parallel marker task number. 646 uint32_t maxMarkTaskCount_ {0}; 647 // parallel evacuator task number. 648 uint32_t maxEvacuateTaskCount_ {0}; 649 os::memory::Mutex waitTaskFinishedMutex_; 650 os::memory::ConditionVariable waitTaskFinishedCV_; 651 652 /* 653 * The memory controller providing memory statistics (by allocations and coleections), 654 * which is used for GC heuristics. 655 */ 656 MemController *memController_ {nullptr}; 657 658 // Region allocators. 659 NativeAreaAllocator *nativeAreaAllocator_ {nullptr}; 660 HeapRegionAllocator *heapRegionAllocator_ {nullptr}; 661 662 // The tracker tracking heap object allocation and movement events. 663 HeapTracker *tracker_ {nullptr}; 664 665 IdleData *idleData_; 666 667 #if ECMASCRIPT_ENABLE_HEAP_VERIFY 668 bool isVerifying_ {false}; 669 #endif 670 }; 671 } // namespace panda::ecmascript 672 673 #endif // ECMASCRIPT_MEM_HEAP_H 674