<commit_before>// Copyright 2014 Runtime.JS project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "thread.h"
#include <kernel/kernel.h>
#include <kernel/thread-manager.h>
#include <kernel/mem-manager.h>
#include <kernel/engine.h>
#include <kernel/engines.h>
#include <kernel/platform.h>

namespace rt {

Thread::Thread(ThreadManager* thread_mgr, ResourceHandle<EngineThread> ethread)
    :	thread_mgr_(thread_mgr),
        type_(ethread.get()->type()),
        iv8_(nullptr),
        tpl_cache_(nullptr),
        stack_(GLOBAL_mem_manager()->virtual_allocator().AllocStack()),
        ethread_(ethread),
        exports_(this),
        ref_count_(0),
        terminate_(false),
        parent_promise_id_(0),
        runtime_(0) {
    priority_.Set(1);
}

Thread::~Thread() {
    RT_ASSERT(!"TODO: Make sure it's safe to delete thread object first!");
}

ExternalFunction* FunctionExports::Add(v8::Local<v8::Value> v,
                                       ResourceHandle<EngineThread> recv) {
    uint32_t index = data_.size();
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };
    RT_ASSERT(iv8);
    size_t export_id = ++export_id_;
    data_.push_back(std::move(FunctionExportData(iv8, v, export_id)));
    return new ExternalFunction(index, export_id, thread_, recv);
}

v8::Local<v8::Value> FunctionExports::Get(uint32_t index, size_t export_id) {
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };

    RT_ASSERT(index < data_.size());
    v8::EscapableHandleScope scope(iv8);
    if (data_[index].export_id() != export_id) {
        return scope.Escape(v8::Local<v8::Value>());
    }

    return scope.Escape(data_[index].GetValue(iv8));
}

void Thread::SetUp() {
    // Skip initialization for idle thread
    if (ThreadType::IDLE == type_) {
        return;
    }

    RT_ASSERT(nullptr == iv8_);
    RT_ASSERT(nullptr == tpl_cache_);
    iv8_ = v8::Isolate::New();
    iv8_->SetData(0, this);
    printf("[V8] new isolate\n");
    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);
    tpl_cache_ = new TemplateCache(iv8_);
}

void Thread::TearDown() {
    RT_ASSERT(ThreadType::DEFAULT == type_);
    RT_ASSERT(iv8_);
    RT_ASSERT(iv8_->GetData(0) == this);
    RT_ASSERT(tpl_cache_);

    {	v8::Isolate::Scope ivscope(iv8_);
        v8::HandleScope local_handle_scope(iv8_);

        auto promise_id = parent_promise_id();
        auto thread = parent_thread();

        LockingPtr<EngineThread> lptr { thread.get() };
        Thread* recv { lptr->thread() };
        RT_ASSERT(recv);

        TransportData data;
        if (!exit_value_.IsEmpty()) {
            TransportData::SerializeError err { data.MoveValue(this, recv,
                v8::Local<v8::Value>::New(iv8_, exit_value_)) };
        }

        {	std::unique_ptr<ThreadMessage> msg(new ThreadMessage(
                ThreadMessage::Type::FUNCTION_RETURN_RESOLVE,
                handle(),
                std::move(data), nullptr, promise_id));
            lptr->PushMessage(std::move(msg));
        }
    }

    RT_ASSERT(thread_mgr_);
    RT_ASSERT(this == thread_mgr_->current_thread());

    timeout_data_.Clear();
    irq_data_.Clear();
    promises_.Clear();

    printf("[V8] delete context\n");
    context_.Reset();
    args_.Reset();
    exit_value_.Reset();
    call_wrapper_.Reset();

    RT_ASSERT(tpl_cache_);
    delete tpl_cache_;

    RT_ASSERT(iv8_);
    printf("[V8] delete isolate\n");
    iv8_->Dispose(); // This deletes v8 isolate object

    type_ = ThreadType::TERMINATED;
}

v8::Local<v8::Object> Thread::GetIsolateGlobal() {
    v8::EscapableHandleScope scope(iv8_);
    auto s_isolate = v8::String::NewFromUtf8(iv8_, "isolate");

    auto context = v8::Local<v8::Context>::New(iv8_, context_);
    RT_ASSERT(!context.IsEmpty());
    auto isolate_value = context->Global()->Get(s_isolate);
    RT_ASSERT(!isolate_value.IsEmpty());
    RT_ASSERT(isolate_value->IsObject());
    return scope.Escape(isolate_value->ToObject());
}

bool Thread::Run() {
    // Not possible to run terminated thread
    RT_ASSERT(ThreadType::TERMINATED != type_);

    // Idle thread does nothing and never terminates
    if (ThreadType::IDLE == type_) {
        return true;
    }

    RT_ASSERT(iv8_);
    RT_ASSERT(tpl_cache_);


    uint64_t time_now { GLOBAL_platform()->BootTimeMicroseconds() };

    EngineThread::ThreadMessagesVector messages = ethread_.get()->TakeMessages();
    if (0 == messages.size()) {
        return true;
    }

    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);

    if (context_.IsEmpty()) {
        printf("[V8] new context\n");
        v8::Local<v8::Context> context = tpl_cache_->NewContext();
        context_ = std::move(v8::UniquePersistent<v8::Context>(iv8_, context));
    }

    RT_ASSERT(!context_.IsEmpty());
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(iv8_, context_);
    v8::Context::Scope cs(context);

    v8::TryCatch trycatch;
<commit_msg>remove new/delete context debug messages<commit_after>// Copyright 2014 Runtime.JS project authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "thread.h"
#include <kernel/kernel.h>
#include <kernel/thread-manager.h>
#include <kernel/mem-manager.h>
#include <kernel/engine.h>
#include <kernel/engines.h>
#include <kernel/platform.h>

namespace rt {

Thread::Thread(ThreadManager* thread_mgr, ResourceHandle<EngineThread> ethread)
    :	thread_mgr_(thread_mgr),
        type_(ethread.get()->type()),
        iv8_(nullptr),
        tpl_cache_(nullptr),
        stack_(GLOBAL_mem_manager()->virtual_allocator().AllocStack()),
        ethread_(ethread),
        exports_(this),
        ref_count_(0),
        terminate_(false),
        parent_promise_id_(0),
        runtime_(0) {
    priority_.Set(1);
}

Thread::~Thread() {
    RT_ASSERT(!"TODO: Make sure it's safe to delete thread object first!");
}

ExternalFunction* FunctionExports::Add(v8::Local<v8::Value> v,
                                       ResourceHandle<EngineThread> recv) {
    uint32_t index = data_.size();
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };
    RT_ASSERT(iv8);
    size_t export_id = ++export_id_;
    data_.push_back(std::move(FunctionExportData(iv8, v, export_id)));
    return new ExternalFunction(index, export_id, thread_, recv);
}

v8::Local<v8::Value> FunctionExports::Get(uint32_t index, size_t export_id) {
    RT_ASSERT(thread_);
    v8::Isolate* iv8 { thread_->IsolateV8() };

    RT_ASSERT(index < data_.size());
    v8::EscapableHandleScope scope(iv8);
    if (data_[index].export_id() != export_id) {
        return scope.Escape(v8::Local<v8::Value>());
    }

    return scope.Escape(data_[index].GetValue(iv8));
}

void Thread::SetUp() {
    // Skip initialization for idle thread
    if (ThreadType::IDLE == type_) {
        return;
    }

    RT_ASSERT(nullptr == iv8_);
    RT_ASSERT(nullptr == tpl_cache_);
    iv8_ = v8::Isolate::New();
    iv8_->SetData(0, this);
    printf("[V8] new isolate\n");
    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);
    tpl_cache_ = new TemplateCache(iv8_);
}

void Thread::TearDown() {
    RT_ASSERT(ThreadType::DEFAULT == type_);
    RT_ASSERT(iv8_);
    RT_ASSERT(iv8_->GetData(0) == this);
    RT_ASSERT(tpl_cache_);

    {	v8::Isolate::Scope ivscope(iv8_);
        v8::HandleScope local_handle_scope(iv8_);

        auto promise_id = parent_promise_id();
        auto thread = parent_thread();

        LockingPtr<EngineThread> lptr { thread.get() };
        Thread* recv { lptr->thread() };
        RT_ASSERT(recv);

        TransportData data;
        if (!exit_value_.IsEmpty()) {
            TransportData::SerializeError err { data.MoveValue(this, recv,
                v8::Local<v8::Value>::New(iv8_, exit_value_)) };
        }

        {	std::unique_ptr<ThreadMessage> msg(new ThreadMessage(
                ThreadMessage::Type::FUNCTION_RETURN_RESOLVE,
                handle(),
                std::move(data), nullptr, promise_id));
            lptr->PushMessage(std::move(msg));
        }
    }

    RT_ASSERT(thread_mgr_);
    RT_ASSERT(this == thread_mgr_->current_thread());

    timeout_data_.Clear();
    irq_data_.Clear();
    promises_.Clear();

    context_.Reset();
    args_.Reset();
    exit_value_.Reset();
    call_wrapper_.Reset();

    RT_ASSERT(tpl_cache_);
    delete tpl_cache_;

    RT_ASSERT(iv8_);
    printf("[V8] delete isolate\n");
    iv8_->Dispose(); // This deletes v8 isolate object

    type_ = ThreadType::TERMINATED;
}

v8::Local<v8::Object> Thread::GetIsolateGlobal() {
    v8::EscapableHandleScope scope(iv8_);
    auto s_isolate = v8::String::NewFromUtf8(iv8_, "isolate");

    auto context = v8::Local<v8::Context>::New(iv8_, context_);
    RT_ASSERT(!context.IsEmpty());
    auto isolate_value = context->Global()->Get(s_isolate);
    RT_ASSERT(!isolate_value.IsEmpty());
    RT_ASSERT(isolate_value->IsObject());
    return scope.Escape(isolate_value->ToObject());
}

bool Thread::Run() {
    // Not possible to run terminated thread
    RT_ASSERT(ThreadType::TERMINATED != type_);

    // Idle thread does nothing and never terminates
    if (ThreadType::IDLE == type_) {
        return true;
    }

    RT_ASSERT(iv8_);
    RT_ASSERT(tpl_cache_);


    uint64_t time_now { GLOBAL_platform()->BootTimeMicroseconds() };

    EngineThread::ThreadMessagesVector messages = ethread_.get()->TakeMessages();
    if (0 == messages.size()) {
        return true;
    }

    v8::Isolate::Scope ivscope(iv8_);
    v8::HandleScope local_handle_scope(iv8_);

    if (context_.IsEmpty()) {
        v8::Local<v8::Context> context = tpl_cache_->NewContext();
        context_ = std::move(v8::UniquePersistent<v8::Context>(iv8_, context));
    }

    RT_ASSERT(!context_.IsEmpty());
    v8::Local<v8::Context> context = v8::Local<v8::Context>::New(iv8_, context_);
    v8::Context::Scope cs(context);

    v8::TryCatch trycatch;

{'fraction_non_alphanumeric': 0.14427092790993282, 'fraction_numerical': 0.016342836390049027, 'mean_word_length': 3.4487075928917608, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7208449', 'n_tokens_mistral': 3563, 'n_tokens_neox': 3508, 'n_words': 702}