LWNode_Release_210726_a33b69e 67/261767/2 accepted/tizen/unified/20210726.135432 submit/tizen/20210726.043438
authorRyan Hyun Choi <ryan.choi@samsung.com>
Mon, 26 Jul 2021 04:07:18 +0000 (13:07 +0900)
committerRyan Hyun Choi <ryan.choi@samsung.com>
Mon, 26 Jul 2021 04:19:09 +0000 (13:19 +0900)
Change-Id: I11fe7a29e3b5ec37e6aadf9faa4126f773f46292
Signed-off-by: Ryan Choi <ryan.choi@samsung.com>
27 files changed:
common.gypi
configure.py
lwnode/code/escargotshim/common.gypi
lwnode/code/escargotshim/deps/escargot/src/api/EscargotPublic.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/PromiseObject.cpp
lwnode/code/escargotshim/deps/escargot/src/runtime/VMInstance.h
lwnode/code/escargotshim/include/v8-profiler.h
lwnode/code/escargotshim/include/v8.h
lwnode/code/escargotshim/src/api-data.cc
lwnode/code/escargotshim/src/api-environment.cc
lwnode/code/escargotshim/src/api-handles.cc
lwnode/code/escargotshim/src/api-template.cc
lwnode/code/escargotshim/src/api.cc
lwnode/code/escargotshim/src/api/context.cc
lwnode/code/escargotshim/src/api/engine.cc
lwnode/code/escargotshim/src/api/engine.h
lwnode/code/escargotshim/src/api/global-handles.cc
lwnode/code/escargotshim/src/api/global-handles.h
lwnode/code/escargotshim/src/api/handle.cc
lwnode/code/escargotshim/src/api/handle.h
lwnode/code/escargotshim/src/api/handlescope.cc
lwnode/code/escargotshim/src/api/isolate.cc
lwnode/code/escargotshim/src/api/isolate.h
lwnode/code/escargotshim/src/api/utils/gc.cc
lwnode/code/escargotshim/src/api/utils/logger.h
lwnode/code/escargotshim/src/libplatform/tracing/trace-buffer.h
tools/gyp_node.py

index 4745bb5..2ef53fd 100644 (file)
             }],
           ],
         },
-        'cflags': [ '-O3' ],
+        'cflags': [ '-Os' ],
         'conditions': [
           ['OS=="linux"', {
             'conditions': [
index 61ddbf1..4e3e8d5 100755 (executable)
@@ -1974,7 +1974,10 @@ if options.compile_commands_json:
 # pass the leftover positional arguments to GYP
 gyp_args += args
 # @lwnode
-gyp_args += get_lwnode_gyp_options()
+if options.without_bundled_v8:
+  gyp_args += get_lwnode_gyp_options()
+else:
+  gyp_args += ['-Dlwnode='+ 'false']
 # @end of lwnode
 
 if warn.warned and not options.verbose:
index 6b78b9f..b83ea33 100755 (executable)
@@ -7,10 +7,10 @@
     'build_asan%': '0',
   },
   'target_defaults': {
-    'defines': [],
+    'defines': [ 'LWNODE=1' ],
     'cflags!': [ '-Wno-error' ],
     'cflags': [
-      '-Wall', '-Wextra', '-Werror',
+      '-Wall', '-Wextra', '-Werror', '-ggdb',
       '-Wno-unused-variable',
       '-Wno-unused-function',
       '-Wno-unused-but-set-variable',
     },
     'configurations': {
       'Debug': {
-        'cflags': [ '-g', '-O0', '-Werror' ],
+        'cflags': [ '-O0' ],
       },
       'Release': {
         'defines': ['NDEBUG'],
-        'cflags': [ '-Wfatal-errors' ],
+        'cflags': [ '-Wfatal-errors', '-Os' ],
       },
     },
     'conditions': [
@@ -39,7 +39,7 @@
             '-Wl,-z,relro,-z,now',
           ],
           'cflags': [
-            '-g', '-O0',
+            '-ggdb', '-Os',
             '-fPIC', '-fPIE',
             '-fstack-protector-strong',
             '-D_FORTIFY_SOURCE=2',
index 01e6a9d..47e31dd 100644 (file)
@@ -926,6 +926,11 @@ Evaluator::EvaluatorResult Evaluator::executeFunction(ContextRef* ctx, ValueRef*
     return toEvaluatorResultRef(result);
 }
 
+COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::Init == (int)VMInstance::PromiseHookType::Init, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::Resolve == (int)VMInstance::PromiseHookType::Resolve, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::Before == (int)VMInstance::PromiseHookType::Before, "");
+COMPILE_ASSERT((int)VMInstanceRef::PromiseHookType::After == (int)VMInstance::PromiseHookType::After, "");
+
 PersistentRefHolder<VMInstanceRef> VMInstanceRef::create(PlatformRef* platform, const char* locale, const char* timezone, const char* baseCacheDir)
 {
     return PersistentRefHolder<VMInstanceRef>(toRef(new VMInstance(new PlatformBridge(platform), locale, timezone, baseCacheDir)));
@@ -2944,7 +2949,11 @@ Uint8ClampedArrayObjectRef* Uint8ClampedArrayObjectRef::create(ExecutionStateRef
 
 PromiseObjectRef* PromiseObjectRef::create(ExecutionStateRef* state)
 {
-    return toRef(new PromiseObject(*toImpl(state)));
+    auto promise = new PromiseObject(*toImpl(state));
+    if (UNLIKELY(toImpl(state)->context()->vmInstance()->isPromiseHookRegistered())) {
+        toImpl(state)->context()->vmInstance()->triggerPromiseHook(*toImpl(state), VMInstance::PromiseHookType::Init, promise);
+    }
+    return toRef(promise);
 }
 
 COMPILE_ASSERT((int)PromiseObjectRef::PromiseState::Pending == (int)PromiseObject::PromiseState::Pending, "");
@@ -2978,11 +2987,17 @@ ObjectRef* PromiseObjectRef::then(ExecutionStateRef* state, ValueRef* onFulfille
 
 void PromiseObjectRef::fulfill(ExecutionStateRef* state, ValueRef* value)
 {
+    if (UNLIKELY(toImpl(state)->context()->vmInstance()->isPromiseHookRegistered())) {
+        toImpl(state)->context()->vmInstance()->triggerPromiseHook(*toImpl(state), VMInstance::PromiseHookType::Resolve, toImpl(this));
+    }
     toImpl(this)->fulfill(*toImpl(state), toImpl(value));
 }
 
 void PromiseObjectRef::reject(ExecutionStateRef* state, ValueRef* reason)
 {
+    if (UNLIKELY(toImpl(state)->context()->vmInstance()->isPromiseHookRegistered())) {
+        toImpl(state)->context()->vmInstance()->triggerPromiseHook(*toImpl(state), VMInstance::PromiseHookType::Resolve, toImpl(this));
+    }
     toImpl(this)->reject(*toImpl(state), toImpl(reason));
 }
 
index dca3a69..273366c 100644 (file)
@@ -279,7 +279,7 @@ static Value promiseResolveFunctions(ExecutionState& state, Value thisValue, siz
     PromiseObject* promise = promiseValue.asObject()->asPromiseObject();
 
     if (UNLIKELY(state.context()->vmInstance()->isPromiseHookRegistered())) {
-        state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Resolve, promise, Value());
+        state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Resolve, promise);
     }
 
     // Let alreadyResolved be F.[[AlreadyResolved]].
@@ -336,7 +336,7 @@ static Value promiseRejectFunctions(ExecutionState& state, Value thisValue, size
     PromiseObject* promise = promiseValue.asObject()->asPromiseObject();
 
     if (UNLIKELY(state.context()->vmInstance()->isPromiseHookRegistered())) {
-        state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Resolve, promise, Value());
+        state.context()->vmInstance()->triggerPromiseHook(state, VMInstance::PromiseHookType::Resolve, promise);
     }
 
     // Let alreadyResolved be F.[[AlreadyResolved]].
index b1a9e69..cfd6d6b 100644 (file)
@@ -305,7 +305,7 @@ public:
         m_promiseHookPublic = nullptr;
     }
 
-    void triggerPromiseHook(ExecutionState& state, PromiseHookType type, PromiseObject* promise, const Value& parent)
+    void triggerPromiseHook(ExecutionState& state, PromiseHookType type, PromiseObject* promise, const Value& parent = Value())
     {
         ASSERT(!!m_promiseHook);
         if (m_promiseHookPublic) {
index c3b25e8..5a52315 100644 (file)
@@ -1050,7 +1050,7 @@ class V8_EXPORT CodeEventHandler {
   CodeEventHandler();
   CodeEventHandler(const CodeEventHandler&);
   CodeEventHandler& operator=(const CodeEventHandler&);
-  void* internal_listener_;
+  void* internal_listener_ = nullptr;
 };
 
 }  // namespace v8
index e10ba15..c137dab 100644 (file)
@@ -1211,9 +1211,9 @@ class V8_EXPORT HandleScope {
   void operator delete(void*, size_t);
   void operator delete[](void*, size_t);
 
-  internal::Isolate* isolate_;
-  internal::Address* prev_next_;
-  internal::Address* prev_limit_;
+  internal::Isolate* isolate_ = nullptr;
+  internal::Address* prev_next_ = nullptr;
+  internal::Address* prev_limit_ = nullptr;
 
   // Local::New uses CreateHandle with an Isolate* parameter.
   template<class F> friend class Local;
@@ -1262,7 +1262,7 @@ class V8_EXPORT EscapableHandleScope : public HandleScope {
   void operator delete[](void*, size_t);
 
   internal::Address* Escape(internal::Address* escape_value);
-  internal::Address* escape_slot_;
+  internal::Address* escape_slot_ = nullptr;
 };
 
 /**
@@ -1286,9 +1286,9 @@ class V8_EXPORT SealHandleScope {
   void operator delete(void*, size_t);
   void operator delete[](void*, size_t);
 
-  internal::Isolate* const isolate_;
-  internal::Address* prev_limit_;
-  int prev_sealed_level_;
+  internal::Isolate* const isolate_ = nullptr;
+  internal::Address* prev_limit_ = nullptr;
+  int prev_sealed_level_ = 0;
 };
 
 
@@ -2384,7 +2384,7 @@ class V8_EXPORT ValueSerializer {
 
  private:
   struct PrivateData;
-  PrivateData* private_;
+  PrivateData* private_ = nullptr;
 };
 
 /**
@@ -2481,7 +2481,7 @@ class V8_EXPORT ValueDeserializer {
 
  private:
   struct PrivateData;
-  PrivateData* private_;
+  PrivateData* private_ = nullptr;
 };
 
 
@@ -7038,7 +7038,7 @@ class V8_EXPORT Extension {  // NOLINT
  private:
   const char* name_;
   size_t source_length_;  // expected to initialize before source_
-  String::ExternalOneByteStringResource* source_;
+  String::ExternalOneByteStringResource* source_ = nullptr;
   int dep_count_;
   const char** deps_;
   bool auto_enable_;
@@ -7699,8 +7699,8 @@ class V8_EXPORT HeapStatistics {
   bool does_zap_garbage_;
   size_t number_of_native_contexts_;
   size_t number_of_detached_contexts_;
-  size_t total_global_handles_size_;
-  size_t used_global_handles_size_;
+  size_t total_global_handles_size_ = 0;
+  size_t used_global_handles_size_ = 0;
 
   friend class V8;
   friend class Isolate;
@@ -8347,7 +8347,7 @@ class V8_EXPORT Isolate {
 
    private:
     OnFailure on_failure_;
-    void* internal_;
+    void* internal_ = nullptr;
   };
 
 
@@ -8366,9 +8366,9 @@ class V8_EXPORT Isolate {
         const AllowJavascriptExecutionScope&) = delete;
 
    private:
-    void* internal_throws_;
-    void* internal_assert_;
-    void* internal_dump_;
+    void* internal_throws_ = nullptr;
+    void* internal_assert_ = nullptr;
+    void* internal_dump_ = nullptr;
   };
 
   /**
@@ -8388,9 +8388,9 @@ class V8_EXPORT Isolate {
         const SuppressMicrotaskExecutionScope&) = delete;
 
    private:
-    internal::Isolate* const isolate_;
-    internal::MicrotaskQueue* const microtask_queue_;
-    internal::Address previous_stack_height_;
+    internal::Isolate* const isolate_ = nullptr;
+    internal::MicrotaskQueue* const microtask_queue_ = nullptr;
+    internal::Address previous_stack_height_ = 0;
 
     friend class internal::ThreadLocalTop;
   };
@@ -8409,7 +8409,7 @@ class V8_EXPORT Isolate {
     SafeForTerminationScope& operator=(const SafeForTerminationScope&) = delete;
 
    private:
-    internal::Isolate* isolate_;
+    internal::Isolate* isolate_ = nullptr;
     bool prev_value_;
   };
 
@@ -9986,7 +9986,7 @@ class V8_EXPORT SnapshotCreator {
   size_t AddData(Local<Context> context, internal::Address object);
   size_t AddData(internal::Address object);
 
-  void* data_;
+  void* data_ = nullptr;
 };
 
 /**
@@ -10260,7 +10260,7 @@ class V8_EXPORT TryCatch {
   TryCatch* next_;
   void* exception_;
   void* message_obj_;
-  void* js_stack_comparable_address_;
+  void* js_stack_comparable_address_ = nullptr;
   bool is_verbose_ : 1;
   bool can_continue_ : 1;
   bool capture_message_ : 1;
index 3632f8a..2fab46c 100644 (file)
@@ -1686,6 +1686,11 @@ MaybeLocal<Object> Function::NewInstanceWithSideEffectType(
   LWNODE_RETURN_LOCAL(Object);
 }
 
+static inline std::string toStdStringWithoutException(ContextRef* context,
+                                                      ValueRef* esValue) {
+  return esValue->toStringWithoutException(context)->toStdUTF8String();
+}
+
 MaybeLocal<v8::Value> Function::Call(Local<Context> context,
                                      v8::Local<v8::Value> recv,
                                      int argc,
@@ -1693,7 +1698,7 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
   API_ENTER_WITH_CONTEXT(context, MaybeLocal<Value>());
   LWNODE_CHECK(CVAL(this)->value()->isCallable());
 
-  auto lwContext = VAL(*context)->context();
+  auto esContext = VAL(*context)->context()->get();
 
   GCVector<ValueRef*> arguments;
   for (int i = 0; i < argc; i++) {
@@ -1701,7 +1706,7 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
   }
 
   auto r = Evaluator::execute(
-      lwContext->get(),
+      esContext,
       [](ExecutionStateRef* state,
          ValueRef* self,
          ValueRef* receiver,
@@ -1714,7 +1719,35 @@ MaybeLocal<v8::Value> Function::Call(Local<Context> context,
       arguments.size(),
       arguments.data());
 
-  API_HANDLE_EXCEPTION(r, lwIsolate, MaybeLocal<Value>());
+  if (!r.isSuccessful()) {
+    LWNODE_DLOG_ERROR("Evaluate");
+    LWNODE_DLOG_RAW("Internal:\n  this: %p (es: %p)\n  recv: %p (es: %p)",
+                    this,
+                    CVAL(this)->value(),
+                    *recv,
+                    CVAL(*recv)->value());
+
+    LWNODE_DLOG_RAW("  arguments (%d):", argc);
+    for (int i = 0; i < argc; i++) {
+      auto esValue = VAL(*argv[i])->value();
+      LWNODE_DLOG_RAW("  [%d] %p (es: %p) %s",
+                      i,
+                      *argv[i],
+                      esValue,
+                      toStdStringWithoutException(esContext, esValue).c_str());
+    }
+
+    LWNODE_DLOG_RAW("Execute:\n  %s (%s:%d)\nResource:\n  %s\n%s",
+                    TRACE_ARGS2,
+                    "N/A",
+                    EvalResultHelper::getErrorString(
+                        lwIsolate->GetCurrentContext()->get(), r)
+                        .c_str());
+
+    lwIsolate->SetPendingExceptionAndMessage(r.error.get(), r.stackTraceData);
+    lwIsolate->ReportPendingMessages();
+    return MaybeLocal<Value>();
+  }
 
   return Utils::NewLocal<Value>(lwIsolate->toV8(), r.result);
 }
index 5fb71d4..5754db2 100644 (file)
@@ -320,6 +320,7 @@ Local<External> v8::External::New(Isolate* isolate, void* value) {
 void* External::Value() const {
   auto esObject = CVAL(this)->value()->asObject();
 
+  LWNODE_CHECK(ObjectRefHelper::getExtraData(esObject));
   auto externalObjectData =
       ObjectRefHelper::getExtraData(esObject)->asExternalObjectData();
 
@@ -1141,12 +1142,6 @@ MaybeLocal<Promise::Resolver> Promise::Resolver::New(Local<Context> context) {
       [](ExecutionStateRef* state,
          EscargotShim::IsolateWrap* lwIsolate) -> ValueRef* {
         auto promise = PromiseObjectRef::create(state);
-
-        // NOTE: Update RunPromiseHook to be called from Escargot after Escargot
-        // supports this feature
-        lwIsolate->RunPromiseHook(
-            PromiseHookType::kInit, promise, ValueRef::createUndefined());
-
         return promise;
       },
       lwIsolate);
@@ -1176,10 +1171,6 @@ Maybe<bool> Promise::Resolver::Resolve(Local<Context> context,
          PromiseObjectRef* promise,
          ValueRef* esValue,
          EscargotShim::IsolateWrap* lwIsolate) -> ValueRef* {
-        // NOTE: Update RunPromiseHook to be called from Escargot after Escargot
-        // supports this feature
-        lwIsolate->RunPromiseHook(PromiseHookType::kResolve, promise, esValue);
-
         promise->fulfill(state, esValue);
         return ValueRef::createUndefined();
       },
@@ -1207,10 +1198,6 @@ Maybe<bool> Promise::Resolver::Reject(Local<Context> context,
          PromiseObjectRef* promise,
          ValueRef* esValue,
          EscargotShim::IsolateWrap* lwIsolate) -> ValueRef* {
-        // NOTE: Update RunPromiseHook to be called from Escargot after Escargot
-        // supports this feature
-        lwIsolate->RunPromiseHook(PromiseHookType::kResolve, promise, esValue);
-
         promise->reject(state, esValue);
         return ValueRef::createUndefined();
       },
@@ -1772,7 +1759,12 @@ Local<Symbol> v8::Symbol::For(Isolate* isolate, Local<String> name) {
 }
 
 Local<Symbol> v8::Symbol::ForApi(Isolate* isolate, Local<String> name) {
-  LWNODE_RETURN_LOCAL(Symbol);
+  API_ENTER_NO_EXCEPTION(isolate);
+
+  SymbolRef* esSymbol =
+      lwIsolate->getApiSymbol(VAL(*name)->value()->asString());
+
+  return Utils::NewLocal<Symbol>(isolate, esSymbol);
 }
 
 #define WELL_KNOWN_SYMBOLS(V)                                                  \
@@ -1814,7 +1806,7 @@ Local<Private> v8::Private::New(Isolate* isolate, Local<String> name) {
   // @todo For now, we ignore the private attribute and use a normal Symbol
   // instead.
 
-  SymbolRef* esSymbol = lwIsolate->getPrivateSymbol(esName);
+  SymbolRef* esSymbol = lwIsolate->createApiPrivateSymbol(esName);
 
   return Utils::NewLocal<Private>(isolate, esSymbol);
 }
@@ -1823,7 +1815,7 @@ Local<Private> v8::Private::ForApi(Isolate* isolate, Local<String> name) {
   API_ENTER_NO_EXCEPTION(isolate);
 
   SymbolRef* esSymbol =
-      lwIsolate->getPrivateSymbol(VAL(*name)->value()->asString());
+      lwIsolate->getApiPrivateSymbol(VAL(*name)->value()->asString());
 
   return Utils::NewLocal<Private>(isolate, esSymbol);
 }
@@ -1896,10 +1888,6 @@ bool Isolate::InContext() {
 }
 
 void Isolate::ClearKeptObjects() {
-#if !defined(GC_HEAP_TRACE_ONLY)
-  MemoryUtil::gc();
-  MemoryUtil::gcInvokeFinalizers();
-#endif
   LWNODE_RETURN_VOID;
 }
 
@@ -1997,7 +1985,7 @@ void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
 }
 
 void Isolate::RequestGarbageCollectionForTesting(GarbageCollectionType type) {
-  LWNODE_RETURN_VOID;
+  IsolateWrap::GetCurrent()->CollectGarbage();
 }
 
 Isolate* Isolate::GetCurrent() {
@@ -2017,6 +2005,7 @@ void Isolate::Initialize(Isolate* isolate,
 }
 
 Isolate* Isolate::New(const Isolate::CreateParams& params) {
+  LWNODE_CALL_TRACE();
   Isolate* isolate = Allocate();
   Initialize(isolate, params);
   return isolate;
@@ -2035,10 +2024,12 @@ void Isolate::DiscardThreadSpecificMetadata() {
 }
 
 void Isolate::Enter() {
+  LWNODE_CALL_TRACE();
   IsolateWrap::fromV8(this)->Enter();
 }
 
 void Isolate::Exit() {
+  LWNODE_CALL_TRACE();
   IsolateWrap::fromV8(this)->Exit();
 }
 
@@ -2490,9 +2481,7 @@ void MicrotasksScope::PerformCheckpoint(Isolate* v8_isolate) {
   auto lwIsolate = IsolateWrap::fromV8(v8_isolate);
   auto vmInstance = lwIsolate->vmInstance();
 
-  if (vmInstance->hasPendingJob() == false) {
-    return;
-  }
+  GCHeap::ProcessingHoldScope scope;
 
   while (vmInstance->hasPendingJob()) {
     auto r = vmInstance->executePendingJob();
index 19a1260..1d42960 100644 (file)
@@ -38,7 +38,7 @@ void HandleScope::Initialize(Isolate* isolate) {
 
 HandleScope::~HandleScope() {
   LWNODE_CALL_TRACE_UNINDENT();
-  LWNODE_CALL_TRACE();
+  LWNODE_CALL_TRACE("%p", this);
   IsolateWrap::fromV8(isolate_)->popHandleScope(this);
 }
 
@@ -79,7 +79,23 @@ i::Address* HandleScope::CreateHandle(i::Isolate* isolate, i::Address value) {
 
   LWNODE_CHECK(handle->isValid());
 
-  lwIsolate->addHandleToCurrentScope(handle);
+  switch (handle->location()) {
+    case HandleWrap::Location::Local:
+      lwIsolate->addHandleToCurrentScope(handle);
+      return reinterpret_cast<i::Address*>(handle);
+
+    case HandleWrap::Location::Strong:
+    case HandleWrap::Location::Weak: {
+      auto cloned = handle->clone(HandleWrap::Location::Local);
+      lwIsolate->addHandleToCurrentScope(cloned);
+      return reinterpret_cast<i::Address*>(cloned);
+    }
+
+    default:
+      break;
+  }
+
+  LWNODE_CHECK_NOT_REACH_HERE();
 
   return reinterpret_cast<i::Address*>(value);
 }
@@ -146,10 +162,12 @@ void SealHandleScope::operator delete[](void*, size_t) {
 }
 
 void Context::Enter() {
+  LWNODE_CALL_TRACE("%s", VAL(this)->getHandleInfoString().c_str());
   VAL(this)->context()->Enter();
 }
 
 void Context::Exit() {
+  LWNODE_CALL_TRACE();
   VAL(this)->context()->Exit();
 }
 
index 416c3ae..8f6801b 100644 (file)
@@ -117,6 +117,8 @@ static ValueRef* FunctionTemplateNativeFunction(
   if (!fnData->checkSignature(state, thisValue)) {
     IsolateWrap::GetCurrent()->ScheduleThrow(TypeErrorObjectRef::create(
         state, StringRef::createFromASCII("Illegal invocation")));
+    LWNODE_DLOG_ERROR("Signature mismatch!");
+    return ValueRef::createUndefined();
   }
 
   Local<Value> result;
index a98a54c..f554f69 100644 (file)
@@ -281,8 +281,13 @@ void ResourceConstraints::set_max_semi_space_size_in_kb(size_t limit_in_kb) {
 i::Address* V8::GlobalizeReference(i::Isolate* isolate, i::Address* obj) {
   LWNODE_CALL_TRACE();
   LWNODE_CHECK(isolate);
+#if defined(GC_HEAP_TRACE_ONLY)
+  auto persistent = PersistentWrap::GlobalizeReference(
+      reinterpret_cast<Isolate*>(isolate), obj);
+  return reinterpret_cast<i::Address*>(persistent);
+#endif
+
   IsolateWrap::fromV8(isolate)->globalHandles()->Create(VAL(obj));
-  Engine::current()->gcHeap()->GlobalizeReference(obj, isolate);
   return obj;
 }
 
@@ -317,28 +322,38 @@ void V8::MakeWeak(i::Address* location,
                   WeakCallbackType type) {
   LWNODE_CALL_TRACE();
 
-  Engine::current()->gcHeap()->MakeWeak(
-      location, parameter, weak_callback, type);
+#if defined(GC_HEAP_TRACE_ONLY)
+  PersistentWrap::MakeWeak(location, parameter, weak_callback);
+  return;
+#endif
 
 #if defined(LWNODE_ENABLE_EXPERIMENTAL)
   if (type != WeakCallbackType::kParameter) {
     LWNODE_RETURN_VOID;  // TODO
   }
-
   GlobalHandles::MakeWeak(VAL(location), parameter, weak_callback);
-#else
-  LWNODE_RETURN_VOID;
 #endif
 }
 
 void V8::MakeWeak(i::Address** location_addr) {
+#if defined(LWNODE_ENABLE_EXPERIMENTAL)
+  GlobalHandles::MakeWeak(
+      VAL(*location_addr), reinterpret_cast<void*>(location_addr), nullptr);
+#endif
   LWNODE_RETURN_VOID;
 }
 
 void* V8::ClearWeak(i::Address* location) {
   LWNODE_CALL_TRACE();
-  Engine::current()->gcHeap()->ClearWeak(location);
+#if defined(GC_HEAP_TRACE_ONLY)
+  return PersistentWrap::ClearWeak(location);
+#endif
+
+#if defined(LWNODE_ENABLE_EXPERIMENTAL)
+  return GlobalHandles::ClearWeakness(VAL(location));
+#else
   LWNODE_RETURN_NULLPTR;
+#endif
 }
 
 void V8::AnnotateStrongRetainer(i::Address* location, const char* label) {
@@ -347,8 +362,12 @@ void V8::AnnotateStrongRetainer(i::Address* location, const char* label) {
 
 void V8::DisposeGlobal(i::Address* location) {
   LWNODE_CALL_TRACE();
+#if defined(GC_HEAP_TRACE_ONLY)
+  PersistentWrap::DisposeGlobal(location);
+  return;
+#endif
+
   GlobalHandles::Destroy(VAL(location));
-  Engine::current()->gcHeap()->DisposeGlobal(location);
 }
 
 void V8::DisposeTracedGlobal(internal::Address* location) {
index 448d76b..85db923 100644 (file)
@@ -31,7 +31,8 @@ static void evalJavaScript(ContextRef* context,
   ScriptParserRef::InitializeScriptResult scriptResult =
       context->scriptParser()->initializeScript(
           StringRef::createExternalFromASCII(buffer, bufferSize),
-          StringRef::createFromASCII(name, sizeof(name)));
+          StringRef::createFromASCII(name,
+                                     strnlen(name, v8::String::kMaxLength)));
   LWNODE_CHECK_MSG(scriptResult.isSuccessful(),
                    "Cannot parser %s: %s",
                    name,
index 558a0b0..5122b4b 100644 (file)
@@ -17,6 +17,7 @@
 #include "engine.h"
 #include <iomanip>
 #include <sstream>
+#include "handle.h"
 #include "utils/logger.h"
 #include "utils/misc.h"
 #include "utils/string.h"
@@ -81,142 +82,106 @@ void Platform::hostImportModuleDynamically(ContextRef* relatedContext,
 }
 
 // --- G C H e a p ---
-#if !defined(GC_HEAP_TRACE_ONLY)
+
 #define GC_WRAP_PERSISTENT_POINTER(p) (GC_heap_pointer)(p)
-#define GC_UNWRAP_POINTER(p) ((void*)p)
-#else
-#define GC_WRAP_PERSISTENT_POINTER(p) GC_HIDE_POINTER(p)
-#define GC_UNWRAP_POINTER(p) ((void*)GC_HIDE_POINTER(p))
-#endif
+#define GC_UNWRAP_PERSISTENT_POINTER(p) ((void*)p)
+#define GC_WRAP_WEAK_POINTER(p) (GC_heap_pointer)(p)
+#define GC_UNWRAP_WEAK_POINTER(p) ((void*)p)
 
 /*
-  @note gc heap tracing lifetime
-
-  a) The types of heap tracing are strong, weak and phantom weak.
-  b) Every persitent is created as strong type at the registration.
-     Following flow is considered:
-
-     i)   strong <-> weak <-> phantom weak -> (finalizer) -> nullptr
-     ii)  strong -> nullptr
-     iii) phantom weak -> strong
-
-  If weak counter is 1, then the pointer will be phantom weak which is
-  collectable for GC.
+  state diagram:
+  FREE -> STRONG <-> WEAK -> (Post GC Processing) -> { STRONG, WEAK, FREE }
 */
 
-void GCHeap::GlobalizeReference(void* address, void* data) {
-  LWNODE_CALL_TRACE("address %p, data %p", address, data);
+void GCHeap::acquire(void* address, Kind kind, void* data) {
+  LWNODE_CALL_TRACE_ID(
+      GCHEAP,
+      "%s kind %u data %p",
+      PersistentWrap::as(address)->getPersistentInfoString().c_str(),
+      kind,
+      data);
+
   auto iter = persistents_.find(GC_WRAP_PERSISTENT_POINTER(address));
   if (iter != persistents_.end()) {
-    iter->second.strong++;
-    iter->second.weak--;
-    iter->second.weak = std::max(iter->second.weak, 0);
-    // no-progress handling weak phantoms
+    if (kind == STRONG) iter->second.strong++;
+    if (kind == WEAK) iter->second.weak++;
   } else {
-    auto iter = weakPhantoms_.find(GC_HIDE_POINTER(address));
+    auto iter = weakPhantoms_.find(GC_WRAP_WEAK_POINTER(address));
     if (iter != weakPhantoms_.end()) {
-      // move phantom weak to strong
       AddressInfo info = iter->second;
 
       LWNODE_CHECK(info.strong == 0);
-      LWNODE_CHECK(info.weak == 1);
-      info.strong++;
-      info.weak--;
+      LWNODE_CHECK(info.weak != 0);
+
+      if (kind == STRONG) iter->second.strong++;
+      if (kind == WEAK) iter->second.weak++;
 
       persistents_.emplace(GC_WRAP_PERSISTENT_POINTER(address), info);
       weakPhantoms_.erase(iter);
-      // no-progress handling weak phantoms
     } else {
       persistents_.emplace(GC_WRAP_PERSISTENT_POINTER(address),
                            AddressInfo(1, 0, data));
     }
   }
-  notifyUpdate(address);
+  postUpdate(address);
 }
 
-void GCHeap::DisposeGlobal(void* address) {
-  LWNODE_CALL_TRACE("address %p", address);
+void GCHeap::release(void* address, Kind kind) {
+  LWNODE_CALL_TRACE_ID(
+      GCHEAP,
+      "%s kind %u",
+      PersistentWrap::as(address)->getPersistentInfoString().c_str(),
+      kind);
+
   auto iter = persistents_.find(GC_WRAP_PERSISTENT_POINTER(address));
   if (iter != persistents_.end()) {
-    iter->second.strong--;
+    if (kind == STRONG) iter->second.strong--;
+    if (kind == WEAK) iter->second.weak--;
+
     iter->second.strong = std::max(iter->second.strong, 0);
+    iter->second.weak = std::max(iter->second.weak, 0);
 
     // progress handling weak phantoms
     if (iter->second.strong == 0) {
-      if (iter->second.weak == 0) {
-        persistents_.erase(iter);
-      } else if (iter->second.weak <= 1) {
-        weakPhantoms_.emplace(GC_HIDE_POINTER(address), iter->second);
-        persistents_.erase(iter);
+      if (iter->second.weak > 0) {
+        weakPhantoms_.emplace(GC_WRAP_WEAK_POINTER(address), iter->second);
       }
-    }
-  }
-  notifyUpdate(address);
-}
-
-void GCHeap::MakeWeak(void* address) {
-  LWNODE_CALL_TRACE("address %p", address);
-  auto iter = persistents_.find(GC_WRAP_PERSISTENT_POINTER(address));
-  if (iter != persistents_.end()) {
-    iter->second.strong--;
-    iter->second.strong = std::max(iter->second.strong, 0);
-    iter->second.weak++;
-
-    // progress handling weak phantoms
-    if (iter->second.strong == 0 && iter->second.weak <= 1) {
-      weakPhantoms_.emplace(GC_HIDE_POINTER(address), iter->second);
       persistents_.erase(iter);
     }
-  } else {
-    auto iter = weakPhantoms_.find(GC_HIDE_POINTER(address));
-    if (iter != weakPhantoms_.end()) {
-      // move phantom weak to weak
-      AddressInfo info = iter->second;
-
-      LWNODE_CHECK(info.strong == 0);
-      LWNODE_CHECK(info.weak == 1);
-      info.weak++;
-
-      persistents_.emplace(GC_WRAP_PERSISTENT_POINTER(address), info);
-      weakPhantoms_.erase(iter);
-    } else {
-      LWNODE_CHECK(false);  // assumes this doesn't happen. let's see.
-    }
   }
-
-  notifyUpdate(address);
+  postUpdate(address);
 }
 
-void GCHeap::ClearWeak(void* address) {
-  LWNODE_CALL_TRACE("address %p", address);
-  // 1. handle persistents_ and weakPhantoms_
-  auto iter = persistents_.find(GC_WRAP_PERSISTENT_POINTER(address));
-  if (iter != persistents_.end()) {
-    // guard: ClearWeak can be called even if no weak reference exist.
-    if (iter->second.weak > 0) {
-      iter->second.weak--;
-    }
-
-    // progress handling weak phantoms
-    if (iter->second.strong <= 0 && iter->second.weak <= 1) {
-      weakPhantoms_.emplace(GC_HIDE_POINTER(address), iter->second);
-      persistents_.erase(iter);
-    }
+void GCHeap::postGarbageCollectionProcessing() {
+  if (isOnPostGarbageCollectionProcessing_ ||
+      ProcessingHoldScope::isSkipProcessing()) {
+    return;
   }
 
-  // 2. ensure clearing finalizer bound to this address
-  MemoryUtil::gcRegisterFinalizer(address, nullptr, nullptr);
+  LWNODE_CALL_TRACE_ID(
+      GCHEAP, "last: %zu, current: %zu", stat_.weak, weakPhantoms_.size());
+  if (stat_.weak == weakPhantoms_.size()) {
+    return;
+  }
+  isOnPostGarbageCollectionProcessing_ = true;
 
-  notifyUpdate(address);
-}
+  // 1. move weaks to process post task.
+  GCVector<HeapSegment> weaks;
+  weaks.reserve(weakPhantoms_.size());
+  for (const HeapSegment& it : weakPhantoms_) {
+    weaks.push_back(it);
+  }
+  weakPhantoms_.clear();
 
-void GCHeap::disposePhantomWeak(void* address) {
-  LWNODE_CALL_TRACE("address %p", address);
-  auto iter = weakPhantoms_.find(GC_HIDE_POINTER(address));
-  if (iter != weakPhantoms_.end()) {
-    weakPhantoms_.erase(iter);
+  // 2. invoke finalizers
+  for (const auto& iter : weaks) {
+    PersistentWrap* persistent =
+        PersistentWrap::as(GC_UNWRAP_PERSISTENT_POINTER(iter.first));
+    persistent->invokeFinalizer();
   }
-  notifyUpdate(address);
+
+  stat_.weak = weakPhantoms_.size();
+  isOnPostGarbageCollectionProcessing_ = false;
 }
 
 bool GCHeap::isTraced(void* address) {
@@ -225,28 +190,29 @@ bool GCHeap::isTraced(void* address) {
     return true;
   }
 
-  if (weakPhantoms_.find(GC_HIDE_POINTER(address)) != weakPhantoms_.end()) {
+  if (weakPhantoms_.find(GC_WRAP_WEAK_POINTER(address)) !=
+      weakPhantoms_.end()) {
     return true;
   }
+
   return false;
 }
 
-void* GCHeap::getPersistentData(void* address) {
-  auto iter = persistents_.find(GC_WRAP_PERSISTENT_POINTER(address));
-  if (iter != persistents_.end()) {
-    return iter->second.data;
-  }
-
-  auto iterWeak = weakPhantoms_.find(GC_HIDE_POINTER(address));
-  if (iterWeak != weakPhantoms_.end()) {
-    return iterWeak->second.data;
+void GCHeap::disposePhantomWeak(void* address) {
+  LWNODE_CALL_TRACE_ID(
+      GCHEAP,
+      "%s",
+      PersistentWrap::as(address)->getPersistentInfoString().c_str());
+  stat_.freed++;
+  auto iter = weakPhantoms_.find(GC_WRAP_WEAK_POINTER(address));
+  if (iter != weakPhantoms_.end()) {
+    weakPhantoms_.erase(iter);
   }
-  return nullptr;
+  postUpdate(address);
 }
 
-typedef void (*formatterFunction)(
-    std::stringstream& stream,
-    const std::pair<GCHeap::GC_heap_pointer, GCHeap::AddressInfo>& iter);
+typedef void (*formatterFunction)(std::stringstream& stream,
+                                  const GCHeap::HeapSegment& iter);
 
 static void printAddress(
     const GCUnorderedMap<GCHeap::GC_heap_pointer, GCHeap::AddressInfo>& map,
@@ -270,94 +236,74 @@ static void printAddress(
   }
 }
 
-void GCHeap::printStatus() {
-  if (isStatusPrinted) {
+void GCHeap::printStatus(bool forcePrint) {
+  if (Flags::isTraceCallEnabled("GCHEAP") == false) {
     return;
   }
-  isStatusPrinted = true;
 
-  if (persistents_.size() == 0 && weakPhantoms_.size() == 0) {
+  if (!forcePrint && isStatePrinted_) {
+    return;
+  }
+
+  isStatePrinted_ = true;
+
+  if (!forcePrint || (persistents_.size() == 0 && weakPhantoms_.size() == 0)) {
     return;
   }
 
-  LWNODE_LOG_INFO(COLOR_GREEN "----- GCHEAP -----" COLOR_RESET);
-  LWNODE_LOG_INFO("[HOLD]");
-  printAddress(
-      persistents_,
-      [](std::stringstream& stream,
-         const std::pair<GCHeap::GC_heap_pointer, GCHeap::AddressInfo>& iter) {
-        stream << std::setw(15) << std::right << GC_UNWRAP_POINTER(iter.first)
-               << " ("
-               << "S" << std::setw(3) << iter.second.strong << " W"
-               << std::setw(3) << iter.second.weak << ") ";
-      });
-
-  LWNODE_LOG_INFO(COLOR_GREEN "------------------" COLOR_RESET);
-  LWNODE_LOG_INFO("[PHANTOM]");
-  printAddress(
-      weakPhantoms_,
-      [](std::stringstream& stream,
-         const std::pair<GCHeap::GC_heap_pointer, GCHeap::AddressInfo>& iter) {
-        stream << std::setw(15) << std::right << GC_REVEAL_POINTER(iter.first)
-               << " ("
-               << "S" << std::setw(3) << iter.second.strong << " W"
-               << std::setw(3) << iter.second.weak << ") ";
-      });
-
-  LWNODE_LOG_INFO(COLOR_GREEN "------------------" COLOR_RESET);
+  LWNODE_DLOG_INFO(COLOR_GREEN "----- GCHEAP -----" COLOR_RESET);
+  LWNODE_DLOG_INFO("[STAT]");
+  LWNODE_DLOG_INFO("     freed: %zu", stat_.freed);
+  LWNODE_DLOG_INFO("    strong: %zu", persistents_.size());
+  LWNODE_DLOG_INFO("      weak: %zu", weakPhantoms_.size());
+  LWNODE_DLOG_INFO("[HOLD]");
+  printAddress(persistents_,
+               [](std::stringstream& stream, const HeapSegment& iter) {
+                 stream << std::setw(15) << std::right
+                        << GC_UNWRAP_PERSISTENT_POINTER(iter.first) << " ("
+                        << "S" << std::setw(3) << iter.second.strong << " W"
+                        << std::setw(3) << iter.second.weak << ") ";
+               });
+
+  LWNODE_DLOG_INFO(COLOR_GREEN "------------------" COLOR_RESET);
+  LWNODE_DLOG_INFO("[PHANTOM]");
+  printAddress(weakPhantoms_,
+               [](std::stringstream& stream, const HeapSegment& iter) {
+                 stream << std::setw(15) << std::right
+                        << GC_UNWRAP_WEAK_POINTER(iter.first) << " ("
+                        << "S" << std::setw(3) << iter.second.strong << " W"
+                        << std::setw(3) << iter.second.weak << ") ";
+               });
+
+  LWNODE_DLOG_INFO(COLOR_GREEN "------------------" COLOR_RESET);
 }
 
-void GCHeap::notifyUpdate(void* address) {
-  isStatusPrinted = false;
+void GCHeap::postUpdate(void* address) {
+  isStatePrinted_ = false;
 }
 
-void GCHeap::MakeWeak(void* location,
-                      void* parameter,
-                      v8::WeakCallbackInfo<void>::Callback weak_callback,
-                      v8::WeakCallbackType type) {
-  LWNODE_CALL_TRACE("address %p", location);
+void GCHeap::processGCEvent() {
+  auto gcHeap = Engine::current()->gcHeap();
+  gcHeap->printStatus();
+  gcHeap->postGarbageCollectionProcessing();
+}
 
-  if (type != v8::WeakCallbackType::kParameter) {
-    LWNODE_CHECK(false);
-  }
+std::vector<GCHeap::ProcessingHoldScope*>
+    GCHeap::ProcessingHoldScope::s_processingHoldScopes_;
 
-#if !defined(GC_HEAP_TRACE_ONLY)
-  // 1. register the given finalizer
-  struct Params {
-    v8::Isolate* isolate;
-    void* parameter;
-    v8::WeakCallbackInfo<void>::Callback weak_callback;
-  };
-
-  Params* params = new Params();
-
-  LWNODE_CHECK(isTraced(location));
-
-  v8::Isolate* v8Isolate =
-      reinterpret_cast<v8::Isolate*>(getPersistentData(location));
-
-  LWNODE_CHECK_NOT_NULL(v8Isolate);
-
-  params->isolate = v8Isolate;
-  params->parameter = parameter;
-  params->weak_callback = weak_callback;
-
-  MemoryUtil::gcRegisterFinalizer(
-      location,
-      [](void* address, void* data) {
-        Engine::current()->gcHeap()->disposePhantomWeak(address);
-        Params* params = (Params*)data;
-        void* embedderFields[v8::kEmbedderFieldsInWeakCallback] = {};
-        v8::WeakCallbackInfo<void> info(
-            params->isolate, params->parameter, embedderFields, nullptr);
-        params->weak_callback(info);
-        delete params;
-      },
-      params);
-#endif
+GCHeap::ProcessingHoldScope::ProcessingHoldScope() {
+  s_processingHoldScopes_.push_back(this);
+}
 
-  // 2. make this location as weak type
-  MakeWeak(location);
+GCHeap::ProcessingHoldScope::~ProcessingHoldScope() {
+  s_processingHoldScopes_.pop_back();
+}
+
+bool GCHeap::ProcessingHoldScope::isSkipProcessing() {
+  if (s_processingHoldScopes_.empty()) {
+    return false;
+  }
+  return true;
 }
 
 // --- E n g i n e ---
@@ -365,11 +311,13 @@ void GCHeap::MakeWeak(void* location,
 static Engine* s_engine;
 std::unordered_set<v8::String::ExternalStringResourceBase*>
     Engine::s_externalStrings;
+static Engine::State s_state = Engine::Freed;
 
 bool Engine::Initialize() {
   if (s_engine == nullptr) {
     s_engine = new Engine();
     s_engine->initialize();
+    s_state = Running;
   }
   return true;
 }
@@ -381,7 +329,7 @@ bool Engine::Dispose() {
     delete s_engine;
     s_engine = nullptr;
   }
-
+  s_state = Freed;
   LWNODE_CALL_TRACE_GC_END();
   return true;
 }
@@ -403,23 +351,23 @@ void Engine::initialize() {
 
   Globals::initialize();
   Memory::setGCFrequency(GC_FREE_SPACE_DIVISOR);
-  gcHeap_.reset(new GCHeap());
+  gcHeap_.reset(GCHeap::create());
 
-  if (Flags::isTraceCallEnabled("HEAP")) {
-    Memory::setGCEventListener([]() {
-      // this is invoked at GC_EVENT_RECLAIM_END phase
-      Engine::current()->gcHeap()->printStatus();
-    });
-  }
+#if defined(GC_HEAP_TRACE_ONLY)
+  // this is invoked at GC_EVENT_RECLAIM_END phase
+  Memory::setGCEventListener(GCHeap::processGCEvent);
+#endif
 
   auto flags = Flags::get();
   if (Flags::isTraceGCEnabled()) {
-    MemoryUtil::gcStartStatsTrace();
+    LWNODE_DLOG_WARN("temporary blocked for postGarbageCollectionProcessing");
+    // MemoryUtil::gcStartStatsTrace();
   }
 }
 
 void Engine::dispose() {
   LWNODE_CALL_TRACE_GC_START();
+  s_state = OnDestroy;
 
   Memory::setGCEventListener(nullptr);
 
@@ -437,6 +385,10 @@ Engine* Engine::current() {
   return s_engine;
 }
 
+Engine::State Engine::getState() {
+  return s_state;
+}
+
 void Engine::registerExternalString(
     v8::String::ExternalStringResourceBase* v8Str) {
   s_externalStrings.emplace(v8Str);
index e4c8981..b5f3102 100644 (file)
@@ -62,24 +62,14 @@ class Platform : public PlatformRef {
   v8::ArrayBuffer::Allocator* allocator_ = nullptr;
 };
 
-#define GC_HEAP_TRACE_ONLY
-
 class GCHeap : public gc {
  public:
-  void GlobalizeReference(void* address, void* data);
-  void DisposeGlobal(void* address);
-  void MakeWeak(void* address);
-  void MakeWeak(void* location,
-                void* parameter,
-                v8::WeakCallbackInfo<void>::Callback weak_callback,
-                v8::WeakCallbackType type);
-  void ClearWeak(void* address);
-  void disposePhantomWeak(void* address);
-  bool isTraced(void* address);
-  void* getPersistentData(void* address);
-  void printStatus();
+  enum Kind {
+    FREE = 0,
+    STRONG,
+    WEAK,
+  };
 
-  typedef GC_word GC_heap_pointer;
   struct AddressInfo {
     AddressInfo(int strong_, int weak_, void* data_ = nullptr) {
       strong = strong_;
@@ -90,13 +80,44 @@ class GCHeap : public gc {
     int weak = 0;
     void* data = nullptr;
   };
+  typedef GC_word GC_heap_pointer;
+  typedef std::pair<GC_heap_pointer, AddressInfo> HeapSegment;
+
+  void acquire(void* address, Kind kind, void* data);
+  void release(void* address, Kind kind);
+  void disposePhantomWeak(void* address);
+  bool isTraced(void* address);
+  void printStatus(bool forcePrint = false);
+
+  class ProcessingHoldScope {
+   public:
+    ProcessingHoldScope();
+    ~ProcessingHoldScope();
+
+    static bool isSkipProcessing();
+
+   private:
+    static std::vector<ProcessingHoldScope*> s_processingHoldScopes_;
+  };
+
+  void postGarbageCollectionProcessing();
+  static void processGCEvent();
+
+  static GCHeap* create() { return new GCHeap(); }
 
  private:
-  void notifyUpdate(void* address);
+  void postUpdate(void* address);
 
   GCUnorderedMap<GC_heap_pointer, AddressInfo> persistents_;
   GCUnorderedMap<GC_heap_pointer, AddressInfo> weakPhantoms_;
-  bool isStatusPrinted = false;
+  bool isStatePrinted_ = false;
+  bool isOnPostGarbageCollectionProcessing_ = false;
+  struct Stat {
+    size_t freed = 0;
+    size_t weak = 0;
+  };
+
+  Stat stat_;
 };
 
 class Engine {
@@ -112,6 +133,14 @@ class Engine {
 
   GCHeap* gcHeap() { return gcHeap_.get(); }
 
+  enum State {
+    Freed,
+    Running,
+    OnDestroy,
+  };
+
+  static State getState();
+
  private:
   Engine() = default;
   void initialize();
index 28a500a..fd3ff9f 100644 (file)
@@ -48,6 +48,23 @@ class GlobalWeakHandler {
     return nodeBlock;
   }
 
+  size_t clearWeakValue() {
+    auto weakValuesSize = weakValues_.size();
+    if (weakValuesSize == 0) {
+      return 0;
+    }
+    LWNODE_CALL_TRACE_ID(
+        GLOBALHANDLES, "Clear weak values: %ld", weakValuesSize);
+    for (auto& iter : weakValues_) {
+      iter.second->releaseValue();
+    }
+    return weakValuesSize;
+  }
+
+  bool isWeak(ValueWrap* lwValue) {
+    return weakValues_.find(lwValue) != weakValues_.end();
+  }
+
   void dispose() { weakValues_.clear(); }
 
  private:
@@ -59,55 +76,41 @@ GlobalWeakHandler g_globalWeakHandler;
 
 GlobalHandles::Node::Node(void* parameter,
                           v8::WeakCallbackInfo<void>::Callback callback)
-    : parameter_(parameter), callback_(callback) {
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "New Node(%p)", this);
-}
+    : parameter_(parameter), callback_(callback) {}
 
-GlobalHandles::Node::~Node() {
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Free Node(%p)", this);
-}
+GlobalHandles::Node::~Node() {}
 
-GlobalHandles::NodeBlock::NodeBlock(v8::Isolate* isolate, uint32_t count)
-    : isolate_(isolate), usedNodes_(count) {
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "New NodeBlock(%p)", this);
+GlobalHandles::NodeBlock::NodeBlock(v8::Isolate* isolate,
+                                    ValueWrap* value,
+                                    uint32_t count)
+    : isolate_(isolate), value_(value), usedNodes_(count) {
+  holder_.reset(value_);
 }
 
 GlobalHandles::NodeBlock::~NodeBlock() {
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Free NodeBlock(%p)", this);
-  auto curNode = firstNode_;
-  while (curNode) {
-    auto nextNode = curNode->nextNode();
-    delete curNode;
-    curNode = nextNode;
-  }
+  delete firstNode_;
+  holder_.release();
 }
 
-bool GlobalHandles::NodeBlock::increaseUsage() {
-  return usedNodes_++ == 0;
-}
-
-bool GlobalHandles::NodeBlock::decreaseUsage() {
-  LWNODE_DCHECK(usedNodes_ > 0);
-  return --usedNodes_ == 0;
-}
-
-GlobalHandles::Node* GlobalHandles::NodeBlock::pushNode(ValueWrap* lwValue,
-                                                        Node* node) {
+GlobalHandles::Node* GlobalHandles::NodeBlock::pushNode(Node* node) {
   if (firstNode_ == nullptr) {
     firstNode_ = node;
-    registerWeakCallback(lwValue);
   } else {
     // TODO
-    LWNODE_DLOG_WARN("The weak callback is registered several times.")
+    LWNODE_DLOG_WARN("The weak callback is registered several times.");
+    if (node) {
+      delete node;
+      return nullptr;
+    }
   }
 
   return node;
 }
 
-void GlobalHandles::NodeBlock::registerWeakCallback(ValueWrap* lwValue) {
-  MemoryUtil::gcRegisterFinalizer(lwValue, [](void* self) {
+void GlobalHandles::NodeBlock::registerWeakCallback() {
+  MemoryUtil::gcRegisterFinalizer(value_, [](void* self) {
     LWNODE_CALL_TRACE_GC_START();
-    LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Call weak callback");
+    LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Call weak callback: %p", self);
 
     auto block = g_globalWeakHandler.popBlock(VAL(self));
     if (!block) {
@@ -123,19 +126,19 @@ void GlobalHandles::NodeBlock::registerWeakCallback(ValueWrap* lwValue) {
         v8::WeakCallbackInfo<void> info(
             block->isolate(), curNode->parameter(), embedderFields, nullptr);
         LWNODE_CHECK_NOT_NULL(block->isolate());
-        LWNODE_CALL_TRACE_ID(
-            GLOBALHANDLES, "Call v8 callback: parm(%p)", curNode->parameter());
         curNode->callback()(info);
       }
-
-      if (curNode->nextNode()) {
-        LWNODE_UNIMPLEMENT;  // TODO
-      }
+      // TODO: The weak callback is registered several times.(create nextNode)
     }
     LWNODE_CALL_TRACE_GC_END();
   });
 }
 
+void GlobalHandles::NodeBlock::releaseValue() {
+  registerWeakCallback();
+  holder_.release();
+}
+
 GlobalHandles::GlobalHandles(v8::Isolate* isolate) : isolate_(isolate) {
   g_globalHandlesVector.push_back(this);
 }
@@ -162,7 +165,9 @@ void GlobalHandles::Create(ValueWrap* lwValue) {
   } else {
     ++iter->second;
     // TODO:
-    LWNODE_DLOG_WARN("Persistent value was created multiple times.")
+    LWNODE_CALL_TRACE_ID(GLOBALHANDLES,
+                         "Persistent value was created multiple times: %p",
+                         lwValue);
   }
 }
 
@@ -172,7 +177,7 @@ void GlobalHandles::Destroy(ValueWrap* lwValue) {
       return;
     }
   }
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot destroy: %p", lwValue)
+  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot destroy: %p", lwValue);
 }
 
 bool GlobalHandles::destroy(ValueWrap* lwValue) {
@@ -188,6 +193,15 @@ bool GlobalHandles::destroy(ValueWrap* lwValue) {
   return false;
 }
 
+size_t GlobalHandles::PostGarbageCollectionProcessing(
+    /*const v8::GCCallbackFlags gc_callback_flags*/) {
+#if defined(LWNODE_ENABLE_EXPERIMENTAL)
+  return g_globalWeakHandler.clearWeakValue();
+#else
+  return 0;
+#endif
+}
+
 void GlobalHandles::MakeWeak(ValueWrap* lwValue,
                              void* parameter,
                              v8::WeakCallbackInfo<void>::Callback callback) {
@@ -196,7 +210,7 @@ void GlobalHandles::MakeWeak(ValueWrap* lwValue,
       return;
     }
   }
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot make weak value: %p", lwValue)
+  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot make weak value: %p", lwValue);
 }
 
 bool GlobalHandles::makeWeak(ValueWrap* lwValue,
@@ -207,13 +221,39 @@ bool GlobalHandles::makeWeak(ValueWrap* lwValue,
     return false;
   }
 
-  auto block =
-      std::make_unique<GlobalHandles::NodeBlock>(isolate_, iter->second);
-  block->pushNode(lwValue, new Node(parameter, callback));
+  if (g_globalWeakHandler.isWeak(lwValue)) {
+    return false;
+  }
+
+  auto block = std::make_unique<GlobalHandles::NodeBlock>(
+      isolate_, lwValue, iter->second);
+  block->pushNode(new Node(parameter, callback));
   g_globalWeakHandler.pushBlock(lwValue, std::move(block));
 
+  LWNODE_CALL_TRACE_ID(
+      GLOBALHANDLES, "MakeWeak: %p(%ld)", lwValue, iter->second);
   persistentValues_.erase(iter);
-  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "MakeWeak: %p", lwValue)
+  return true;
+}
+
+void* GlobalHandles::ClearWeakness(ValueWrap* lwValue) {
+  for (auto globalHandles : g_globalHandlesVector) {
+    if (globalHandles->clearWeak(lwValue)) {
+      return lwValue;
+    }
+  }
+  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "Cannot clear weak value: %p", lwValue);
+  return nullptr;
+}
+
+bool GlobalHandles::clearWeak(ValueWrap* lwValue) {
+  auto block = g_globalWeakHandler.popBlock(lwValue);
+  if (!block) {
+    return false;
+  }
+  LWNODE_CHECK(persistentValues_.find(lwValue) == persistentValues_.end());
+  persistentValues_.emplace(lwValue, block->usedNodes());
+  LWNODE_CALL_TRACE_ID(GLOBALHANDLES, "ClearWeak: %p", lwValue);
   return true;
 }
 
index de0a132..82eb645 100644 (file)
@@ -31,6 +31,10 @@ class GlobalHandles final : public gc {
   static void MakeWeak(ValueWrap* lwValue,
                        void* parameter,
                        v8::WeakCallbackInfo<void>::Callback callback);
+  static void* ClearWeakness(ValueWrap* lwValue);
+
+  size_t PostGarbageCollectionProcessing(
+      /*const v8::GCCallbackFlags gc_callback_flags*/);
 
   bool destroy(ValueWrap* lwValue);
 
@@ -38,6 +42,8 @@ class GlobalHandles final : public gc {
                 void* parameter,
                 v8::WeakCallbackInfo<void>::Callback callback);
 
+  bool clearWeak(ValueWrap* lwValue);
+
   size_t handles_count();
 
   void Dispose();
@@ -49,43 +55,41 @@ class GlobalHandles final : public gc {
 
     Node(const Node&) = delete;
 
-    Node* nextNode() { return nextNode_; }
     void* parameter() { return parameter_; }
     v8::WeakCallbackInfo<void>::Callback callback() { return callback_; }
 
    private:
-    Node* nextNode_{nullptr};
     void* parameter_{nullptr};
     v8::WeakCallbackInfo<void>::Callback callback_;
   };
 
   class NodeBlock {
    public:
-    NodeBlock(v8::Isolate* isolate, uint32_t count);
+    NodeBlock(v8::Isolate* isolate, ValueWrap* value, uint32_t count);
 
     ~NodeBlock();
 
     NodeBlock(const NodeBlock&) = delete;
 
-    bool increaseUsage();
-
-    bool decreaseUsage();
-
-    uint32_t usage() { return usedNodes_; }
+    uint32_t usedNodes() { return usedNodes_; }
 
     Node* firstNode() { return firstNode_; }
     void setFirstNode(Node* node) { firstNode_ = node; }
 
-    Node* pushNode(ValueWrap* lwValue, Node* node);
+    Node* pushNode(Node* node);
+
+    void registerWeakCallback();
 
-    void registerWeakCallback(ValueWrap* lwValue);
+    void releaseValue();
 
     v8::Isolate* isolate() { return isolate_; }
 
    private:
     v8::Isolate* isolate_{nullptr};
+    ValueWrap* value_{nullptr};
     uint32_t usedNodes_{0};
     Node* firstNode_{nullptr};
+    Escargot::PersistentRefHolder<ValueWrap> holder_;
   };
 
  private:
index c731b5c..93709e9 100644 (file)
  */
 
 #include "handle.h"
+#include <sstream>
 #include "api.h"
 #include "context.h"
+#include "engine.h"
 #include "isolate.h"
 #include "utils/misc.h"
 
@@ -30,8 +32,53 @@ uint8_t HandleWrap::type() const {
   return type_;
 }
 
+uint8_t HandleWrap::valueType() const {
+  return valueType_;
+}
+
+uint8_t HandleWrap::location() const {
+  return location_;
+}
+
 bool HandleWrap::isValid() const {
-  return (type_ < HandleWrap::Type::NotPresent);
+  return (type_ > Type::NotPresent && type_ < Type::EndOfType);
+}
+
+bool HandleWrap::isStrongOrWeak() const {
+  return (location_ == Strong || location_ == Weak || location_ == NearDeath);
+}
+
+void HandleWrap::copy(HandleWrap* that, Location location) {
+  val_ = that->val_;
+  type_ = that->type_;
+  valueType_ = that->valueType_;
+  location_ = location;
+}
+
+HandleWrap* HandleWrap::clone(Location location) {
+  auto handle = new HandleWrap();
+  handle->val_ = val_;
+  handle->type_ = type_;
+  handle->valueType_ = valueType_;
+  handle->location_ = location;
+
+  LWNODE_CALL_TRACE_ID(
+      HANDLE, "%p is cloned from %s", handle, getHandleInfoString().c_str());
+  return handle;
+}
+
+HandleWrap* HandleWrap::as(void* address) {
+  auto p = reinterpret_cast<HandleWrap*>(address);
+  LWNODE_CHECK(p->isValid());
+  return p;
+}
+
+std::string HandleWrap::getHandleInfoString() {
+  std::stringstream ss;
+  ss << "(addr: " << this << " es: " << val_
+     << " loc: " << std::to_string(location_)
+     << " type: " << std::to_string(type_) << ")";
+  return ss.str();
 }
 
 // --- ValueWrap ---
@@ -41,8 +88,9 @@ ValueWrap::ValueWrap(void* ptr,
                      HandleWrap::ValueType valueType) {
   LWNODE_CHECK_NOT_NULL(ptr);
   type_ = type;
-  holder_ = ptr;
+  val_ = ptr;
   valueType_ = valueType;
+  LWNODE_CALL_TRACE_ID(HANDLE, "%s", getHandleInfoString().c_str());
 }
 
 bool ValueWrap::isExternalString() const {
@@ -55,47 +103,41 @@ ExternalStringWrap* ValueWrap::asExternalString() const {
 }
 
 ValueWrap* ValueWrap::createValue(Escargot::ValueRef* esValue) {
-  auto value = new ValueWrap(esValue, Type::JsValue);
-  LWNODE_CALL_TRACE_ID(VALUEWRAP, "es:%p | %p", esValue, value);
-  return value;
+  return new ValueWrap(esValue, Type::JsValue);
 }
 
 ValueRef* ValueWrap::value() const {
   LWNODE_CHECK_MSG(type() == Type::JsValue,
-                   "type should be %d but %d. (this: %p, holder_: %p)",
+                   "type should be %d but %d. (this: %p, val_: %p)",
                    Type::JsValue,
                    type(),
                    this,
-                   holder_);
-  return reinterpret_cast<ValueRef*>(holder_);
+                   val_);
+  return reinterpret_cast<ValueRef*>(val_);
 }
 
 ValueWrap* ValueWrap::createContext(ContextWrap* lwContext) {
-  auto value = new ValueWrap(lwContext, Type::Context);
-  LWNODE_CALL_TRACE_ID(VALUEWRAP, "es:%p | %p", lwContext, value);
-  return value;
+  return new ValueWrap(lwContext, Type::Context);
 };
 
 ContextWrap* ValueWrap::context() const {
-  LWNODE_CHECK(type() == Type::Context);
-  return reinterpret_cast<ContextWrap*>(holder_);
+  LWNODE_CHECK(type_ == Type::Context);
+  return reinterpret_cast<ContextWrap*>(val_);
 }
 
 ValueWrap* ValueWrap::createScript(ScriptRef* esScript) {
-  auto value = new ValueWrap(esScript, Type::Script);
-  LWNODE_CALL_TRACE_ID(VALUEWRAP, "es:%p | %p", esScript, value);
-  return value;
+  return new ValueWrap(esScript, Type::Script);
 };
 
 ScriptRef* ValueWrap::script() const {
-  LWNODE_CHECK(type() == Type::Script);
-  return reinterpret_cast<ScriptRef*>(holder_);
+  LWNODE_CHECK(type_ == Type::Script);
+  return reinterpret_cast<ScriptRef*>(val_);
 }
 
 Escargot::TemplateRef* ValueWrap::tpl() const {
-  LWNODE_CHECK(type() == Type::ObjectTemplate ||
-               type() == Type::FunctionTemplate);
-  return reinterpret_cast<TemplateRef*>(holder_);
+  LWNODE_CHECK(type_ == Type::ObjectTemplate ||
+               type_ == Type::FunctionTemplate);
+  return reinterpret_cast<TemplateRef*>(val_);
 }
 
 ValueWrap* ValueWrap::createFunctionTemplate(
@@ -104,8 +146,8 @@ ValueWrap* ValueWrap::createFunctionTemplate(
 }
 
 Escargot::FunctionTemplateRef* ValueWrap::ftpl() const {
-  LWNODE_CHECK(type() == Type::FunctionTemplate);
-  return reinterpret_cast<FunctionTemplateRef*>(holder_);
+  LWNODE_CHECK(type_ == Type::FunctionTemplate);
+  return reinterpret_cast<FunctionTemplateRef*>(val_);
 }
 
 ValueWrap* ValueWrap::createObjectTemplate(
@@ -114,8 +156,8 @@ ValueWrap* ValueWrap::createObjectTemplate(
 }
 
 Escargot::ObjectTemplateRef* ValueWrap::otpl() const {
-  LWNODE_CHECK(type() == Type::ObjectTemplate);
-  return reinterpret_cast<ObjectTemplateRef*>(holder_);
+  LWNODE_CHECK(type_ == Type::ObjectTemplate);
+  return reinterpret_cast<ObjectTemplateRef*>(val_);
 }
 
 ValueWrap* ValueWrap::createModule(ModuleWrap* esModule) {
@@ -123,8 +165,208 @@ ValueWrap* ValueWrap::createModule(ModuleWrap* esModule) {
 }
 
 ModuleWrap* ValueWrap::module() const {
-  LWNODE_CHECK(type() == Type::Module);
-  return reinterpret_cast<ModuleWrap*>(holder_);
+  LWNODE_CHECK(type_ == Type::Module);
+  return reinterpret_cast<ModuleWrap*>(val_);
+}
+
+// --- PersistentWrap ---
+
+inline static GCHeap* GCHeap() {
+  return Engine::current()->gcHeap();
+}
+
+inline static void acquireStrong(void* address, void* data = nullptr) {
+  GCHeap()->acquire(address, GCHeap::STRONG, data);
+}
+
+inline static void releaseStrong(void* address) {
+  GCHeap()->release(address, GCHeap::STRONG);
+}
+
+inline static void acquireWeak(void* address, void* data = nullptr) {
+  GCHeap()->acquire(address, GCHeap::WEAK, data);
+}
+
+inline static void releaseWeak(void* address) {
+  GCHeap()->release(address, GCHeap::WEAK);
+}
+
+inline static void makeStrongToWeak(void* address) {
+  acquireWeak(address);
+  releaseStrong(address);
+}
+/*
+  1. val_ : HandleWrap MUST be compatible with in V8 other apis.
+
+  ex1)
+    v8::Persistent<String> global1;
+    global1.Reset(isolate, v8_str("str"));
+    Local<String> local1 = Local<String>::New(isolate, global1);
+    CHECK(global1 == local1);
+
+  ex2)
+    v8::Context* operator->() {
+      return *reinterpret_cast<v8::Context**>(&context_);
+    }
+    v8::Context* operator*() { return operator->(); }
+    v8::Persistent<v8::Context> context_;
+
+  2. member values of this instance MUST be hidden to GC.
+*/
+
+PersistentWrap::PersistentWrap(ValueWrap* lwValue) {
+  // copy the given value information and set it as Strong
+  copy(lwValue, Location::Strong);
+
+  holder_ = lwValue;
+
+  LWNODE_CALL_TRACE_ID(GCHEAP,
+                       "%s trace: (%p)",
+                       getPersistentInfoString().c_str(),
+                       getTracingAddress());
+
+  acquireStrong(this, nullptr);
+  LWNODE_DCHECK(GCHeap()->isTraced(this));
+}
+
+void* PersistentWrap::getTracingAddress() {
+  return this;
+}
+
+void* PersistentWrap::GlobalizeReference(v8::Isolate* isolate, void* address) {
+  LWNODE_CALL_TRACE_ID(GCHEAP);
+  ValueWrap* lwValue = reinterpret_cast<ValueWrap*>(address);
+  LWNODE_CHECK(lwValue->isValid());
+
+  PersistentWrap* persistent = new PersistentWrap(lwValue);
+
+  persistent->v8Isolate_ = isolate;
+
+  GCHeap()->printStatus(true);
+
+  return persistent;
+}
+
+void PersistentWrap::DisposeGlobal(void* address) {
+  PersistentWrap* persistent = reinterpret_cast<PersistentWrap*>(address);
+  LWNODE_CALL_TRACE_ID(
+      GCHEAP, "%s", persistent->getPersistentInfoString().c_str());
+
+  LWNODE_DCHECK(persistent->location_ != Local);
+
+  persistent->dispose();
+
+  GCHeap()->printStatus(true);
+}
+
+void PersistentWrap::dispose() {
+  LWNODE_CALL_TRACE_ID(GCHEAP,
+                       "%s isFinalizerCalled: %s",
+                       getPersistentInfoString().c_str(),
+                       strBool(isFinalizerCalled));
+  if (isFinalizerCalled) {
+    return;
+  }
+
+  if (location_ == Location::Strong) {
+    releaseStrong(getTracingAddress());
+  } else if (location_ == Location::Weak) {
+    releaseWeak(getTracingAddress());
+  } else {
+    LWNODE_CHECK_NOT_REACH_HERE();
+  }
+}
+
+void PersistentWrap::MakeWeak(
+    void* address,
+    void* parameter,
+    v8::WeakCallbackInfo<void>::Callback weak_callback) {
+  LWNODE_CALL_TRACE_ID(GCHEAP);
+  PersistentWrap* persitent = reinterpret_cast<PersistentWrap*>(address);
+  LWNODE_CHECK(persitent->location() != Location::Local);
+  persitent->makeWeak(parameter, weak_callback);
+
+  GCHeap()->printStatus(true);
+}
+
+void PersistentWrap::makeWeak(
+    void* parameter, v8::WeakCallbackInfo<void>::Callback weak_callback) {
+  if (location_ == Location::Strong) {
+    // Strong -> Weak
+    makeStrongToWeak(getTracingAddress());
+    location_ = Location::Weak;
+    parameter_ = parameter;
+    weak_callback_ = weak_callback;
+
+  } else if (location_ == Location::Weak) {
+    LWNODE_CHECK(weak_callback_ == weak_callback);
+    LWNODE_CHECK(parameter_ == parameter);
+
+  } else {
+    LWNODE_CHECK_NOT_REACH_HERE();
+  }
+
+  LWNODE_CHECK(GCHeap()->isTraced(this));
+}
+
+void PersistentWrap::invokeFinalizer() {
+  if (Engine::getState() == Engine::Running) {
+    GCHeap()->disposePhantomWeak(this);
+  }
+
+  v8::HandleScope handleScope(v8Isolate_);
+  void* embedderFields[v8::kEmbedderFieldsInWeakCallback] = {};
+  v8::WeakCallbackInfo<void> data(
+      v8Isolate_, parameter_, embedderFields, nullptr);
+
+  weak_callback_(data);
+
+  isFinalizerCalled = true;
+}
+
+void* PersistentWrap::ClearWeak(void* address) {
+  LWNODE_CALL_TRACE_ID(GCHEAP);
+  PersistentWrap* persitent = reinterpret_cast<PersistentWrap*>(address);
+  LWNODE_CHECK(persitent->location() != Location::Local);
+  void* p = persitent->clearWeak();
+  GCHeap()->printStatus(true);
+  return p;
+}
+
+void* PersistentWrap::clearWeak() {
+  if (location_ == Location::Strong) {
+    // Nothing to do
+    LWNODE_CHECK_NULL(weak_callback_);
+    LWNODE_CHECK_NULL(parameter_);
+
+  } else if (location_ == Location::Weak) {
+    // Weak -> Strong
+    acquireStrong(getTracingAddress(), nullptr);
+    releaseWeak(getTracingAddress());
+    location_ = Location::Strong;
+
+  } else {
+    LWNODE_CHECK_NOT_REACH_HERE();
+  }
+
+  void* p = parameter_;
+  parameter_ = nullptr;
+  weak_callback_ = nullptr;
+  return p;
+}
+
+PersistentWrap* PersistentWrap::as(void* address) {
+  auto p = reinterpret_cast<PersistentWrap*>(address);
+  LWNODE_CHECK(p->isStrongOrWeak());
+  LWNODE_CHECK(p->isValid());
+  return p;
+}
+
+std::string PersistentWrap::getPersistentInfoString() {
+  std::stringstream ss;
+  ss << getHandleInfoString() << " holder: " << holder_;
+
+  return ss.str();
 }
 
 }  // namespace EscargotShim
index a6c7846..533c954 100644 (file)
@@ -26,18 +26,26 @@ class ContextWrap;
 class IsolateWrap;
 class ModuleWrap;
 class ExternalStringWrap;
+class GCHeap;
 
 class HandleWrap : public gc {
  public:
   enum Type : uint8_t {
+    NotPresent = 0,
     JsValue = 101,
     Context,
     ObjectTemplate,
     FunctionTemplate,
     Script,
     Module,
-    // NotPresent should be at last
-    NotPresent,
+    EndOfType,
+  };
+
+  enum Location : uint8_t {
+    Local = 0,
+    Strong,
+    Weak,
+    NearDeath,
   };
 
   enum ValueType : uint8_t {
@@ -46,13 +54,22 @@ class HandleWrap : public gc {
   };
 
   uint8_t type() const;
+  uint8_t valueType() const;
   bool isValid() const;
+  bool isStrongOrWeak() const;
+  uint8_t location() const;
+  HandleWrap* clone(Location location = Local);
+  std::string getHandleInfoString();
+  static HandleWrap* as(void* address);
 
  protected:
   HandleWrap() = default;
-  void* holder_ = nullptr;
+  void copy(HandleWrap* that, Location location);
+
+  void* val_ = nullptr;
   uint8_t type_ = Type::NotPresent;
   uint8_t valueType_ = ValueType::None;  // TODO: remove this variable
+  uint8_t location_ = Location::Local;
 };
 
 class ValueWrap : public HandleWrap {
@@ -97,6 +114,37 @@ class ValueWrap : public HandleWrap {
   ValueWrap(void* ptr,
             HandleWrap::Type type,
             HandleWrap::ValueType valueType = HandleWrap::ValueType::None);
+  ValueWrap() = default;
+};
+
+class PersistentWrap : public ValueWrap {
+ public:
+  static void* GlobalizeReference(v8::Isolate* isolate, void* address);
+  static void DisposeGlobal(void* address);
+  static void MakeWeak(void* address,
+                       void* parameter,
+                       v8::WeakCallbackInfo<void>::Callback weak_callback);
+  static void* ClearWeak(void* address);
+
+  static PersistentWrap* as(void* address);
+  std::string getPersistentInfoString();
+  void invokeFinalizer();
+
+ private:
+  PersistentWrap(ValueWrap* ptr);
+
+  void dispose();
+  void makeWeak(void* parameter,
+                v8::WeakCallbackInfo<void>::Callback weak_callback);
+  void* clearWeak();
+  void* getTracingAddress();
+
+  ValueWrap* holder_{nullptr};
+  v8::Isolate* v8Isolate_{nullptr};
+  v8::WeakCallbackInfo<void>::Callback weak_callback_{nullptr};
+  void* parameter_{nullptr};
+  bool isFinalizerCalled{false};
+  friend class GCHeap;
 };
 
 }  // namespace EscargotShim
index 1f702dc..80985d7 100644 (file)
@@ -37,7 +37,11 @@ HandleScopeWrap::HandleScopeWrap(v8::EscapableHandleScope* scope,
     : type_(type), v8scope_(reinterpret_cast<void*>(scope)) {}
 
 void HandleScopeWrap::add(HandleWrap* value) {
-  LWNODE_CALL_TRACE_ID(HDLSCOPE, "%p -> %p | %p", value, v8scope_, this);
+  LWNODE_CALL_TRACE_ID(HDLSCOPE,
+                       "%s --> %p (lw: %p)",
+                       value->getHandleInfoString().c_str(),
+                       v8scope_,
+                       this);
 
   handles_.push_back(value);
 }
index 3cb180e..8ed4e4d 100755 (executable)
@@ -230,6 +230,7 @@ IsolateWrap* IsolateWrap::New() {
 }
 
 void IsolateWrap::Dispose() {
+  LWNODE_CALL_TRACE_ID(ISOWRAP);
   LWNODE_CALL_TRACE_GC_START();
   // NOTE: check unlock_gc_release(); is needed (and where)
   // unlock_gc_release();
@@ -348,6 +349,7 @@ void IsolateWrap::popHandleScope(v8Scope_t* handleScope) {
 }
 
 void IsolateWrap::addHandleToCurrentScope(HandleWrap* value) {
+  LWNODE_CALL_TRACE("%p", value);
   LWNODE_CHECK(handleScopes_.size() >= 1);
   handleScopes_.back()->add(value);
 }
@@ -371,7 +373,11 @@ bool IsolateWrap::isCurrentScopeSealed() {
 }
 
 void IsolateWrap::pushContext(ContextWrap* context) {
-  LWNODE_CALL_TRACE_ID(ISOWRAP, "%p", context);
+  LWNODE_CALL_TRACE_ID(ISOWRAP,
+                       "%p (%zu -> %zu)",
+                       context,
+                       contextScopes_.size(),
+                       contextScopes_.size() + 1);
 
   if (contextScopes_.size() && (contextScopes_.back() != context)) {
     LWNODE_DLOG_WARN(R"(multiple contexts exist:
@@ -396,7 +402,11 @@ size_t IsolateWrap::getNumberOfContexts() {
 
 void IsolateWrap::popContext(ContextWrap* context) {
   LWNODE_CHECK(contextScopes_.back() == context);
-  LWNODE_CALL_TRACE_ID(ISOWRAP, "%p", context);
+  LWNODE_CALL_TRACE_ID(ISOWRAP,
+                       "%p (%zu -> %zu)",
+                       context,
+                       contextScopes_.size(),
+                       contextScopes_.size() - 1);
   contextScopes_.pop_back();
 }
 
@@ -422,30 +432,82 @@ void IsolateWrap::removeBackingStore(BackingStoreRef* value) {
   backingStores_.erase(value);
 }
 
-SymbolRef* IsolateWrap::getPrivateSymbol(StringRef* esString) {
-  // @check replace this container if this function is called a lot.
+SymbolRef* IsolateWrap::createApiSymbol(StringRef* name) {
+  // FIXME: Use a set
+  auto newSymbol = SymbolRef::create(name);
+  bool found = false;
+  for (size_t i = 0; i < apiSymbols_.size(); i++) {
+    if (apiSymbols_[i]->description()->equals(name)) {
+      apiSymbols_[i] = newSymbol;
+      found = true;
+      break;
+    }
+  }
+
+  if (!found) {
+    apiSymbols_.push_back(newSymbol);
+    LWNODE_DLOG_INFO("malc: api symbol: %s", name->toStdUTF8String().c_str());
+  }
+
+  return newSymbol;
+}
+
+SymbolRef* IsolateWrap::getApiSymbol(StringRef* name) {
+  // FIXME: Use a set
   LWNODE_CALL_TRACE_ID(ISOWRAP);
 
-  for (size_t i = 0; i < privateSymbols_.size(); i++) {
-    if (privateSymbols_[i]->description()->equals(esString)) {
-      return privateSymbols_[i];
+  for (size_t i = 0; i < apiSymbols_.size(); i++) {
+    if (apiSymbols_[i]->description()->equals(name)) {
+      return apiSymbols_[i];
     }
   }
 
-  auto newSymbol = SymbolRef::create(esString);
-  privateSymbols_.push_back(newSymbol);
+  return createApiSymbol(name);
+}
 
-  LWNODE_DLOG_INFO("malc: private symbol: %s",
-                   esString->toStdUTF8String().c_str());
+SymbolRef* IsolateWrap::createApiPrivateSymbol(StringRef* name) {
+  // FIXME: Use a set
+  auto newSymbol = SymbolRef::create(name);
+  bool found = false;
+  for (size_t i = 0; i < apiPrivateSymbols_.size(); i++) {
+    if (apiPrivateSymbols_[i]->description()->equals(name)) {
+      apiPrivateSymbols_[i] = newSymbol;
+      found = true;
+      break;
+    }
+  }
+
+  if (!found) {
+    apiPrivateSymbols_.push_back(newSymbol);
+    LWNODE_DLOG_INFO("malc: private symbol: %s",
+                     name->toStdUTF8String().c_str());
+  }
 
   return newSymbol;
 }
 
+SymbolRef* IsolateWrap::getApiPrivateSymbol(StringRef* name) {
+  // FIXME: Use a set
+  LWNODE_CALL_TRACE_ID(ISOWRAP);
+
+  for (size_t i = 0; i < apiPrivateSymbols_.size(); i++) {
+    if (apiPrivateSymbols_[i]->description()->equals(name)) {
+      return apiPrivateSymbols_[i];
+    }
+  }
+
+  return createApiPrivateSymbol(name);
+}
+
 void IsolateWrap::ClearPendingExceptionAndMessage() {
   clear_pending_exception();
   clear_pending_message_obj();
 }
 
+void IsolateWrap::CollectGarbage() {
+  globalHandles_->PostGarbageCollectionProcessing();
+}
+
 void IsolateWrap::SetPendingExceptionAndMessage(
     ValueRef* exception,
     GCManagedVector<Escargot::Evaluator::StackTraceData>& stackTraceData) {
index f8b8679..7157846 100755 (executable)
@@ -194,10 +194,16 @@ class IsolateWrap final : public v8::internal::Isolate {
   bool isHole(const ValueWrap* wrap) override;
   bool isHole(const Escargot::ValueRef* ref) override;
 
-  SymbolRef* getPrivateSymbol(StringRef* esString);
+  SymbolRef* createApiSymbol(StringRef* name);
+  SymbolRef* getApiSymbol(StringRef* name);
+
+  SymbolRef* createApiPrivateSymbol(StringRef* name);
+  SymbolRef* getApiPrivateSymbol(StringRef* name);
 
   GlobalHandles* globalHandles() { return globalHandles_; }
 
+  void CollectGarbage();
+
   void SetPendingExceptionAndMessage(
       ValueRef* exception,
       GCManagedVector<Escargot::Evaluator::StackTraceData>& stackTraceData)
@@ -224,7 +230,8 @@ class IsolateWrap final : public v8::internal::Isolate {
   GCVector<ContextWrap*> contextScopes_;
 
   PersistentRefHolder<SymbolRef> privateValuesSymbol_;
-  GCVector<Escargot::SymbolRef*> privateSymbols_;
+  GCVector<SymbolRef*> apiSymbols_;
+  GCVector<SymbolRef*> apiPrivateSymbols_;
 
   // Isolate Scope
   static THREAD_LOCAL IsolateWrap* s_currentIsolate;
index e14d474..56b0f2c 100644 (file)
@@ -282,7 +282,7 @@ void MemoryUtil::prettyBytes(char* buf,
   };
   uint s = 0;
   double c = bytes;
-  while (c >= 1024 && s < 7) {
+  while (c >= 1024 && s < 7 - 1) {
     c /= 1024;
     s++;
   }
index 41c2912..ab2aaec 100644 (file)
@@ -83,7 +83,8 @@ class IndentCounter {
   } while (0);
 #endif
 
-#define LWNODE_LOG_INFO(fmt, ...) LWNODE_LOG_RAW("INFO " fmt, ##__VA_ARGS__);
+#define LWNODE_LOG_INFO(fmt, ...)                                              \
+  LWNODE_LOG_RAW("INFO " fmt COLOR_RESET, ##__VA_ARGS__);
 
 #define LWNODE_LOG_WARN(fmt, ...)                                              \
   LWNODE_LOG_RAW(COLOR_YELLOW "WARN " fmt COLOR_RESET, ##__VA_ARGS__);
index 3b4a47e..b951c11 100644 (file)
@@ -56,7 +56,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
   size_t max_chunks_;
   std::unique_ptr<TraceWriter> trace_writer_;
   std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
-  size_t chunk_index_;
+  size_t chunk_index_ = 0;
   bool is_empty_ = true;
   uint32_t current_chunk_seq_ = 1;
 };
index 8c7493f..332a729 100755 (executable)
@@ -34,6 +34,14 @@ def run_gyp(args):
 
   args.append('--depth=' + node_root)
 
+# @lwnode
+  if '-Dnode_core_target_name=lwnode' not in args:
+    global output_dir
+    output_dir = os.path.join(output_dir, 'v8')
+    args.extend(['--generator-output', output_dir])
+    args.extend(['-Goutput_dir=' + output_dir])
+# @end of lwnode
+
   # There's a bug with windows which doesn't allow this feature.
   if sys.platform != 'win32' and 'ninja' not in args:
     # Tell gyp to write the Makefiles into output_dir