Compare commits

...

2 commits

Author SHA1 Message Date
Seonghyun Kim
b379fd475c Update api
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
2022-08-11 15:54:57 +09:00
Seonghyun Kim
c65aed1a97 Update public API
Each thread should call Global::{initialize, finalize} instead of thread version.
Every thread can use different platform.

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
2022-07-06 18:44:34 +09:00
7 changed files with 202 additions and 198 deletions

View file

@ -113,12 +113,13 @@ public:
PlatformBridge(PlatformRef* p)
: m_platform(p)
{
m_platform->ref();
}
virtual ~PlatformBridge()
{
// delete PlatformRef, so we don't care about PlatformRef's lifetime
delete m_platform;
// deref PlatformRef, so we don't care about PlatformRef's lifetime
m_platform->deref();
}
virtual void* onMallocArrayBufferObjectDataBuffer(size_t sizeInByte) override
@ -247,12 +248,24 @@ void* PlatformRef::threadLocalCustomData()
return ThreadLocal::customData();
}
void PlatformRef::ref()
{
m_refCount++;
}
void PlatformRef::deref()
{
if (m_refCount.fetch_sub(1) == 1) {
delete this;
}
}
thread_local bool g_globalsInited;
void Globals::initialize(PlatformRef* platform)
{
// initialize global value or context including thread-local variables
// this function should be invoked once at the start of the program
// argument `platform` will be deleted automatically when Globals::finalize called
// this function should be invoked once at the start of the thread
// argument `platform` will be deleted automatically when Globals::finalize is called and refCount is zero
RELEASE_ASSERT(!g_globalsInited);
Global::initialize(new PlatformBridge(platform));
ThreadLocal::initialize();
@ -262,34 +275,16 @@ void Globals::initialize(PlatformRef* platform)
void Globals::finalize()
{
// finalize global value or context including thread-local variables
// this function should be invoked once at the end of the program
// this function should be invoked once at the end of the thread
RELEASE_ASSERT(!!g_globalsInited);
ThreadLocal::finalize();
// Global::finalize should be called at the end of program
// Global::finalize should be called at the end of thread
// because it holds Platform which could be used in other Object's finalizer
Global::finalize();
g_globalsInited = false;
}
void Globals::initializeThread()
{
// initialize thread-local variables
// this function should be invoked at the start of sub-thread
RELEASE_ASSERT(!g_globalsInited);
ThreadLocal::initialize();
g_globalsInited = true;
}
void Globals::finalizeThread()
{
// finalize thread-local variables
// this function should be invoked once at the end of sub-thread
RELEASE_ASSERT(!!g_globalsInited);
ThreadLocal::finalize();
g_globalsInited = false;
}
bool Globals::supportsThreading()
{
#if defined(ENABLE_THREADING)

View file

@ -39,6 +39,7 @@
#include <type_traits>
#include <utility>
#include <sstream>
#include <atomic>
#if !defined(NDEBUG) && defined(__GLIBCXX__) && !defined(_GLIBCXX_DEBUG)
#pragma message("You should define `_GLIBCXX_DEBUG` in {debug mode + libstdc++} because Escargot uses it")
@ -126,16 +127,11 @@ ESCARGOT_REF_LIST(DECLARE_REF_CLASS);
class ESCARGOT_EXPORT Globals {
public:
// Escargot has thread-independent Globals.
// Users should call initialize, finalize once in the main program
// Escargot has thread-dependent Globals.
// Users should call initialize, finalize once in each thread
static void initialize(PlatformRef* platform);
static void finalize();
// Globals also used for thread initialization
// Users need to call initializeThread, finalizeThread function for each thread
static void initializeThread();
static void finalizeThread();
static bool supportsThreading();
static const char* version();
@ -2157,6 +2153,18 @@ public:
}
void* threadLocalCustomData();
protected:
friend class PlatformBridge;
PlatformRef()
: m_refCount(0)
{
}
void ref();
void deref();
std::atomic_size_t m_refCount;
};
class ESCARGOT_EXPORT WASMOperationsRef {

View file

@ -28,8 +28,11 @@
namespace Escargot {
bool Global::inited;
Platform* Global::g_platform;
#if defined(ENABLE_THREADING)
std::atomic_size_t g_initCount;
#endif
MAY_THREAD_LOCAL bool Global::inited;
MAY_THREAD_LOCAL Platform* Global::g_platform;
#if defined(ENABLE_ATOMICS_GLOBAL_LOCK)
SpinLock Global::g_atomicsLock;
#endif
@ -40,13 +43,14 @@ std::vector<Global::Waiter*> Global::g_waiter;
void Global::initialize(Platform* platform)
{
// initialize should be invoked only once in the program
static bool called_once = true;
RELEASE_ASSERT(called_once && !inited);
RELEASE_ASSERT(!inited);
ASSERT(!g_platform);
g_platform = platform;
#if defined(ENABLE_THREADING)
if (g_initCount.fetch_add(1) == 0) {
#endif
// initialize PointerValue tag values
// tag values should be initialized once and not changed
PointerValue::g_objectTag = Object().getVTag();
@ -61,29 +65,29 @@ void Global::initialize(Platform* platform)
DECLARE_SCRIPTSIMPLEFUNCTION_LIST(INIT_SCRIPTSIMPLEFUNCTION_TAGS);
#undef INIT_SCRIPTSIMPLEFUNCTION_TAGS
#if defined(ENABLE_THREADING)
}
#endif
called_once = false;
inited = true;
}
void Global::finalize()
{
// finalize should be invoked only once in the program
static bool called_once = true;
RELEASE_ASSERT(called_once && inited);
RELEASE_ASSERT(inited);
#if defined(ENABLE_THREADING)
if (g_initCount.fetch_sub(1) == 1) {
for (size_t i = 0; i < g_waiter.size(); i++) {
delete g_waiter[i];
}
std::vector<Waiter*>().swap(g_waiter);
}
#endif
delete g_platform;
g_platform = nullptr;
called_once = false;
inited = false;
}

View file

@ -38,8 +38,8 @@ class Platform;
// Global is a global interface used by all threads
class Global {
static bool inited;
static Platform* g_platform;
static MAY_THREAD_LOCAL bool inited;
static MAY_THREAD_LOCAL Platform* g_platform;
#if defined(ENABLE_ATOMICS_GLOBAL_LOCK)
static SpinLock g_atomicsLock;
#endif

View file

@ -59,6 +59,8 @@ public:
virtual void customInfoLogger(const char* format, va_list arg) = 0;
virtual void customErrorLogger(const char* format, va_list arg) = 0;
#endif
protected:
};
} // namespace Escargot

View file

@ -125,9 +125,7 @@ static void genericGCEventListener(GC_EventType evtType)
void ThreadLocal::initialize()
{
// initialize should be invoked only once in each thread
static MAY_THREAD_LOCAL bool called_once = true;
RELEASE_ASSERT(called_once && !inited);
RELEASE_ASSERT(!inited);
// Heap is initialized for each thread
Heap::initialize();
@ -162,15 +160,12 @@ void ThreadLocal::initialize()
// g_customData
g_customData = Global::platform()->allocateThreadLocalCustomData();
called_once = false;
inited = true;
}
void ThreadLocal::finalize()
{
// finalize should be invoked only once in each thread
static MAY_THREAD_LOCAL bool called_once = true;
RELEASE_ASSERT(called_once && inited);
RELEASE_ASSERT(inited);
// g_customData
Global::platform()->deallocateThreadLocalCustomData();
@ -208,7 +203,6 @@ void ThreadLocal::finalize()
delete g_bumpPointerAllocator;
g_bumpPointerAllocator = nullptr;
called_once = false;
inited = false;
}

View file

@ -271,278 +271,6 @@ static ValueRef* builtinGc(ExecutionStateRef* state, ValueRef* thisValue, size_t
return ValueRef::createUndefined();
}
PersistentRefHolder<ContextRef> createEscargotContext(VMInstanceRef* instance, bool isMainThread = true);
#if defined(ESCARGOT_ENABLE_TEST)
static bool evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool isModule);
static ValueRef* builtinUneval(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argc) {
if (argv[0]->isSymbol()) {
return argv[0]->asSymbol()->symbolDescriptiveString();
}
return argv[0]->toString(state);
}
return StringRef::emptyString();
}
static ValueRef* builtinDrainJobQueue(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
ContextRef* context = state->context();
while (context->vmInstance()->hasPendingJob()) {
auto jobResult = context->vmInstance()->executePendingJob();
if (jobResult.error) {
return ValueRef::create(false);
}
}
return ValueRef::create(true);
}
static ValueRef* builtinAddPromiseReactions(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argc >= 3) {
PromiseObjectRef* promise = argv[0]->toObject(state)->asPromiseObject();
promise->then(state, argv[1], argv[2]);
} else {
state->throwException(TypeErrorObjectRef::create(state, StringRef::emptyString()));
}
return ValueRef::createUndefined();
}
static ValueRef* builtinCreateNewGlobalObject(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
return ContextRef::create(state->context()->vmInstance())->globalObject();
}
static ValueRef* builtin262CreateRealm(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
auto newContext = createEscargotContext(state->context()->vmInstance(), false);
return newContext->globalObject()->get(state, StringRef::createFromASCII("$262"));
}
static ValueRef* builtin262DetachArrayBuffer(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argv[0]->isArrayBufferObject()) {
argv[0]->asArrayBufferObject()->detachArrayBuffer();
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262EvalScript(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
StringRef* src = argv[0]->toString(state);
auto script = state->context()->scriptParser()->initializeScript(src, StringRef::createFromASCII("$262.evalScript input"), false).fetchScriptThrowsExceptionIfParseError(state);
return script->execute(state);
}
static ValueRef* builtin262IsHTMLDDA(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
return ValueRef::createNull();
}
struct WorkerThreadData {
std::string message;
bool running;
volatile bool ended;
WorkerThreadData()
: running(true)
, ended(false)
{
}
};
std::mutex workerMutex;
std::vector<std::pair<std::thread, WorkerThreadData>> workerThreads;
std::vector<std::string> messagesFromWorkers;
static ValueRef* builtin262AgentStart(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::string script = argv[0]->toString(state)->toStdUTF8String();
std::thread worker([](std::string script) {
Globals::initializeThread();
Memory::setGCFrequency(24);
PersistentRefHolder<VMInstanceRef> instance = VMInstanceRef::create();
PersistentRefHolder<ContextRef> context = createEscargotContext(instance.get(), false);
evalScript(context.get(), StringRef::createFromUTF8(script.data(), script.size()),
StringRef::createFromASCII("from main thread"), false, false);
while (true) {
{
bool running = false;
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
running = workerThreads[i].second.running;
break;
}
}
if (!running) {
break;
}
}
// readmessage if exists
std::string message;
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
message = std::move(workerThreads[i].second.message);
break;
}
}
}
if (message.length()) {
std::istringstream istream(message);
ValueRef* val1 = SerializerRef::deserializeFrom(context.get(), istream);
ValueRef* val2 = SerializerRef::deserializeFrom(context.get(), istream);
ValueRef* callback = (ValueRef*)context.get()->globalObject()->extraData();
if (callback) {
Evaluator::execute(context.get(), [](ExecutionStateRef* state, ValueRef* callback, ValueRef* v1, ValueRef* v2) -> ValueRef* {
ValueRef* argv[2] = { v1, v2 };
return callback->call(state, ValueRef::createUndefined(), 2, argv);
},
callback, val1, val2);
}
}
usleep(10 * 1000);
}
context.release();
instance.release();
Globals::finalizeThread();
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
workerThreads[i].second.ended = true;
}
}
},
script);
{
std::lock_guard<std::mutex> guard(workerMutex);
workerThreads.push_back(std::make_pair(std::move(worker), WorkerThreadData()));
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentBroadcast(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::ostringstream ostream;
if (argc > 0) {
SerializerRef::serializeInto(argv[0], ostream);
} else {
SerializerRef::serializeInto(ValueRef::createUndefined(), ostream);
}
if (argc > 1) {
SerializerRef::serializeInto(argv[1], ostream);
} else {
SerializerRef::serializeInto(ValueRef::createUndefined(), ostream);
}
std::string message(ostream.str());
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
workerThreads[i].second.message = message;
}
}
while (true) {
bool thereIsNoMessage = true;
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].second.message.size()) {
thereIsNoMessage = false;
break;
}
}
}
if (thereIsNoMessage) {
break;
}
usleep(10 * 1000); // sleep 10ms
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentReport(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::string message;
if (argc > 0) {
message = argv[0]->toString(state)->toStdUTF8String();
}
std::lock_guard<std::mutex> guard(workerMutex);
messagesFromWorkers.push_back(message);
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentLeaving(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
workerThreads[i].second.running = false;
break;
}
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentReceiveBroadcast(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
state->context()->globalObject()->setExtraData(argv[0]);
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentGetReport(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::lock_guard<std::mutex> guard(workerMutex);
if (messagesFromWorkers.size()) {
std::string message = messagesFromWorkers.front();
messagesFromWorkers.erase(messagesFromWorkers.begin());
return StringRef::createFromUTF8(message.data(), message.size());
} else {
return ValueRef::createNull();
}
}
static ValueRef* builtin262AgentMonotonicNow(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return ValueRef::create((uint64_t)tv.tv_sec * 1000UL + tv.tv_usec / 1000UL);
}
static ValueRef* builtin262AgentSleep(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
double m = argv[0]->toNumber(state);
usleep(m * 1000.0);
return ValueRef::createUndefined();
}
#endif
class ShellPlatform : public PlatformRef {
public:
bool m_canBlock;
@ -671,6 +399,279 @@ private:
}
};
ShellPlatform* g_platform;
PersistentRefHolder<ContextRef> createEscargotContext(VMInstanceRef* instance, bool isMainThread = true);
#if defined(ESCARGOT_ENABLE_TEST)
static bool evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool isModule);
static ValueRef* builtinUneval(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argc) {
if (argv[0]->isSymbol()) {
return argv[0]->asSymbol()->symbolDescriptiveString();
}
return argv[0]->toString(state);
}
return StringRef::emptyString();
}
static ValueRef* builtinDrainJobQueue(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
ContextRef* context = state->context();
while (context->vmInstance()->hasPendingJob()) {
auto jobResult = context->vmInstance()->executePendingJob();
if (jobResult.error) {
return ValueRef::create(false);
}
}
return ValueRef::create(true);
}
static ValueRef* builtinAddPromiseReactions(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argc >= 3) {
PromiseObjectRef* promise = argv[0]->toObject(state)->asPromiseObject();
promise->then(state, argv[1], argv[2]);
} else {
state->throwException(TypeErrorObjectRef::create(state, StringRef::emptyString()));
}
return ValueRef::createUndefined();
}
static ValueRef* builtinCreateNewGlobalObject(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
return ContextRef::create(state->context()->vmInstance())->globalObject();
}
static ValueRef* builtin262CreateRealm(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
auto newContext = createEscargotContext(state->context()->vmInstance(), false);
return newContext->globalObject()->get(state, StringRef::createFromASCII("$262"));
}
static ValueRef* builtin262DetachArrayBuffer(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
if (argv[0]->isArrayBufferObject()) {
argv[0]->asArrayBufferObject()->detachArrayBuffer();
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262EvalScript(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
StringRef* src = argv[0]->toString(state);
auto script = state->context()->scriptParser()->initializeScript(src, StringRef::createFromASCII("$262.evalScript input"), false).fetchScriptThrowsExceptionIfParseError(state);
return script->execute(state);
}
static ValueRef* builtin262IsHTMLDDA(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
return ValueRef::createNull();
}
struct WorkerThreadData {
std::string message;
bool running;
volatile bool ended;
WorkerThreadData()
: running(true)
, ended(false)
{
}
};
std::mutex workerMutex;
std::vector<std::pair<std::thread, WorkerThreadData>> workerThreads;
std::vector<std::string> messagesFromWorkers;
static ValueRef* builtin262AgentStart(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::string script = argv[0]->toString(state)->toStdUTF8String();
std::thread worker([](std::string script) {
Globals::initialize(g_platform);
Memory::setGCFrequency(24);
PersistentRefHolder<VMInstanceRef> instance = VMInstanceRef::create();
PersistentRefHolder<ContextRef> context = createEscargotContext(instance.get(), false);
evalScript(context.get(), StringRef::createFromUTF8(script.data(), script.size()),
StringRef::createFromASCII("from main thread"), false, false);
while (true) {
{
bool running = false;
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
running = workerThreads[i].second.running;
break;
}
}
if (!running) {
break;
}
}
// readmessage if exists
std::string message;
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
message = std::move(workerThreads[i].second.message);
break;
}
}
}
if (message.length()) {
std::istringstream istream(message);
ValueRef* val1 = SerializerRef::deserializeFrom(context.get(), istream);
ValueRef* val2 = SerializerRef::deserializeFrom(context.get(), istream);
ValueRef* callback = (ValueRef*)context.get()->globalObject()->extraData();
if (callback) {
Evaluator::execute(context.get(), [](ExecutionStateRef* state, ValueRef* callback, ValueRef* v1, ValueRef* v2) -> ValueRef* {
ValueRef* argv[2] = { v1, v2 };
return callback->call(state, ValueRef::createUndefined(), 2, argv);
},
callback, val1, val2);
}
}
usleep(10 * 1000);
}
context.release();
instance.release();
Globals::finalize();
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
workerThreads[i].second.ended = true;
}
}
},
script);
{
std::lock_guard<std::mutex> guard(workerMutex);
workerThreads.push_back(std::make_pair(std::move(worker), WorkerThreadData()));
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentBroadcast(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::ostringstream ostream;
if (argc > 0) {
SerializerRef::serializeInto(argv[0], ostream);
} else {
SerializerRef::serializeInto(ValueRef::createUndefined(), ostream);
}
if (argc > 1) {
SerializerRef::serializeInto(argv[1], ostream);
} else {
SerializerRef::serializeInto(ValueRef::createUndefined(), ostream);
}
std::string message(ostream.str());
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
workerThreads[i].second.message = message;
}
}
while (true) {
bool thereIsNoMessage = true;
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].second.message.size()) {
thereIsNoMessage = false;
break;
}
}
}
if (thereIsNoMessage) {
break;
}
usleep(10 * 1000); // sleep 10ms
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentReport(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::string message;
if (argc > 0) {
message = argv[0]->toString(state)->toStdUTF8String();
}
std::lock_guard<std::mutex> guard(workerMutex);
messagesFromWorkers.push_back(message);
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentLeaving(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::lock_guard<std::mutex> guard(workerMutex);
for (size_t i = 0; i < workerThreads.size(); i++) {
if (workerThreads[i].first.get_id() == std::this_thread::get_id()) {
workerThreads[i].second.running = false;
break;
}
}
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentReceiveBroadcast(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
state->context()->globalObject()->setExtraData(argv[0]);
return ValueRef::createUndefined();
}
static ValueRef* builtin262AgentGetReport(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
std::lock_guard<std::mutex> guard(workerMutex);
if (messagesFromWorkers.size()) {
std::string message = messagesFromWorkers.front();
messagesFromWorkers.erase(messagesFromWorkers.begin());
return StringRef::createFromUTF8(message.data(), message.size());
} else {
return ValueRef::createNull();
}
}
static ValueRef* builtin262AgentMonotonicNow(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return ValueRef::create((uint64_t)tv.tv_sec * 1000UL + tv.tv_usec / 1000UL);
}
static ValueRef* builtin262AgentSleep(ExecutionStateRef* state, ValueRef* thisValue, size_t argc, ValueRef** argv, bool isConstructCall)
{
double m = argv[0]->toNumber(state);
usleep(m * 1000.0);
return ValueRef::createUndefined();
}
#endif
static bool evalScript(ContextRef* context, StringRef* source, StringRef* srcName, bool shouldPrintScriptResult, bool isModule)
{
if (stringEndsWith(srcName->toStdUTF8String(), "mjs")) {
@ -937,8 +938,8 @@ int main(int argc, char* argv[])
bool wait_before_exit = false;
ShellPlatform* platform = new ShellPlatform();
Globals::initialize(platform);
g_platform = new ShellPlatform();
Globals::initialize(g_platform);
Memory::setGCFrequency(24);
@ -966,7 +967,7 @@ int main(int argc, char* argv[])
continue;
}
if (strcmp(argv[i], "--canblock-is-false") == 0) {
platform->setCanBlock(false);
g_platform->setCanBlock(false);
continue;
}
if (strstr(argv[i], "--filename-as=") == argv[i]) {