Descriptor: Support async/await in taskpool

Details: Trigger concurrent callback before return

Issue: https://gitee.com/open_harmony/dashboard?issue_id=I6DC6E

Signed-off-by: wengchangcheng <wengchangcheng@huawei.com>
Change-Id: I6377d90157f0452446e932f8c4c1d14ff22c3109
This commit is contained in:
wengchangcheng 2023-02-07 18:36:08 +08:00 committed by Gymee
parent 6d3c60682d
commit 324e8f79c5
11 changed files with 66 additions and 17 deletions

View File

@ -955,4 +955,26 @@ JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
ASSERT(index < internalNativeMethods_.size());
return internalNativeMethods_[index];
}
void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
{
if (concurrentCallback_ == nullptr) {
LOG_ECMA(INFO) << "Only trigger concurrent callback in taskpool thread";
return;
}
if (result.IsJSPromise()) {
// Async concurrent will return Promise
auto promise = JSPromise::Cast(result.GetTaggedObject());
if (promise->GetPromiseState() == PromiseState::PENDING) {
LOG_ECMA(ERROR) << "Promise is in pending state, don't return";
return;
}
result = promise->GetPromiseResult();
}
auto ret = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result));
auto data = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, hint));
concurrentCallback_(ret, data, concurrentData_);
}
} // namespace panda::ecmascript

View File

@ -16,6 +16,8 @@
#ifndef ECMASCRIPT_ECMA_VM_H
#define ECMASCRIPT_ECMA_VM_H
#include <mutex>
#include "ecmascript/base/config.h"
#include "ecmascript/builtins/builtins_method_index.h"
#include "ecmascript/js_handle.h"
@ -23,9 +25,9 @@
#include "ecmascript/js_thread.h"
#include "ecmascript/mem/c_containers.h"
#include "ecmascript/mem/c_string.h"
#include "ecmascript/napi/include/jsnapi.h"
#include "ecmascript/taskpool/taskpool.h"
#include "ecmascript/waiter_list.h"
#include <mutex>
namespace panda {
class JSNApi;
@ -371,6 +373,14 @@ public:
return resolveBufferCallback_;
}
void SetConcurrentCallback(ConcurrentCallback callback, void *data)
{
concurrentCallback_ = callback;
concurrentData_ = data;
}
void TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint);
void AddConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool, int32_t index = 0);
bool HasCachedConstpool(const JSPandaFile *jsPandaFile) const;
@ -655,6 +665,10 @@ private:
ResolvePathCallback resolvePathCallback_ {nullptr};
ResolveBufferCallback resolveBufferCallback_ {nullptr};
// Concurrent taskpool callback and data
ConcurrentCallback concurrentCallback_ {nullptr};
void *concurrentData_ {nullptr};
// vm parameter configurations
EcmaParamConfiguration ecmaParamConfiguration_;
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)

View File

@ -1354,6 +1354,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
methodHandle.Update(JSFunction::Cast(state->function.GetTaggedObject())->GetMethod());
[[maybe_unused]] auto fistPC = methodHandle->GetBytecodeArray();
UPDATE_HOTNESS_COUNTER(-(pc - fistPC));
JSTaggedType *currentSp = sp;
sp = state->base.prev;
ASSERT(sp != nullptr);
@ -1401,6 +1402,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
methodHandle.Update(JSFunction::Cast(state->function.GetTaggedObject())->GetMethod());
[[maybe_unused]] auto fistPC = methodHandle->GetBytecodeArray();
UPDATE_HOTNESS_COUNTER_NON_ACC(-(pc - fistPC));
JSTaggedType *currentSp = sp;
sp = state->base.prev;
ASSERT(sp != nullptr);

View File

@ -21,8 +21,6 @@
namespace panda::ecmascript {
enum class FunctionKind : uint8_t {
NORMAL_FUNCTION = 0,
// Concurrent function is normal function with concurrent property
CONCURRENT_FUNCTION,
// BEGIN accessors
GETTER_FUNCTION,
SETTER_FUNCTION,
@ -32,19 +30,18 @@ enum class FunctionKind : uint8_t {
// BEGIN async functions
ASYNC_ARROW_FUNCTION,
// END arrow functions
// Concurrent function is async function with concurrent property
CONCURRENT_FUNCTION,
ASYNC_FUNCTION,
// END async functions
// BEGIN base constructors
BASE_CONSTRUCTOR,
// BEGIN default constructors
DEFAULT_BASE_CONSTRUCTOR,
// BEGIN class constructors
CLASS_CONSTRUCTOR,
// END base constructors
// BEGIN constructable functions
BUILTIN_PROXY_CONSTRUCTOR,
BUILTIN_CONSTRUCTOR,
// END default constructors
DERIVED_CONSTRUCTOR,
// END class constructors
GENERATOR_FUNCTION,

View File

@ -310,7 +310,7 @@ bool JSSerializer::WriteTaggedObject(const JSHandle<JSTaggedValue> &value)
return WritePlainObject(value);
case JSType::JS_NATIVE_POINTER:
return WriteNativePointer(value);
case JSType::JS_FUNCTION:
case JSType::JS_ASYNC_FUNCTION: // means CONCURRENT_FUNCTION
return WriteJSFunction(value);
case JSType::METHOD:
return WriteMethod(value);
@ -483,7 +483,7 @@ bool JSSerializer::WriteMethod(const JSHandle<JSTaggedValue> &value)
bool JSSerializer::WriteJSFunction(const JSHandle<JSTaggedValue> &value)
{
size_t oldSize = bufferSize_;
if (!WriteType(SerializationUID::JS_FUNCTION)) {
if (!WriteType(SerializationUID::CONCURRENT_FUNCTION)) {
return false;
}
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(value);
@ -1229,7 +1229,7 @@ JSHandle<JSTaggedValue> JSDeserializer::DeserializeJSTaggedValue()
return ReadJSArrayBuffer();
case SerializationUID::TAGGED_OBJECT_REFERNCE:
return ReadReference();
case SerializationUID::JS_FUNCTION:
case SerializationUID::CONCURRENT_FUNCTION:
return ReadJSFunction();
case SerializationUID::TAGGED_ARRAY:
return ReadTaggedArray();
@ -1382,7 +1382,7 @@ JSHandle<JSTaggedValue> JSDeserializer::ReadNativeMethod()
JSHandle<JSTaggedValue> JSDeserializer::ReadJSFunction()
{
JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> func = factory_->NewJSFunction(env);
JSHandle<JSFunction> func = factory_->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION);
JSHandle<JSTaggedValue> funcTag(func);
referenceMap_.emplace(objectId_++, funcTag);
JSHandle<JSTaggedValue> methodVal = DeserializeJSTaggedValue();

View File

@ -94,7 +94,7 @@ enum class SerializationUID : uint8_t {
ERROR_MESSAGE_BEGIN,
ERROR_MESSAGE_END,
// Function begin
JS_FUNCTION,
CONCURRENT_FUNCTION,
JS_METHOD,
NATIVE_METHOD,
CONSTANT_POOL,

View File

@ -38,6 +38,9 @@ class CopyableGlobal;
template<typename T>
class Global;
class JSNApi;
template<typename T>
class Local;
class JSValueRef;
class PrimitiveRef;
class ArrayRef;
class StringRef;
@ -65,6 +68,7 @@ using QuickFixQueryCallBack = bool (*)(std::string, std::string &, void **, size
using EcmaVM = ecmascript::EcmaVM;
using JSThread = ecmascript::JSThread;
using JSTaggedType = uint64_t;
using ConcurrentCallback = void (*)(Local<JSValueRef> val, Local<JSValueRef> hint, void *data);
static constexpr size_t DEFAULT_GC_THREAD_NUM = 7;
static constexpr size_t DEFAULT_LONG_PAUSE_TIME = 40;
@ -1297,6 +1301,7 @@ public:
static void SetAssetPath(EcmaVM *vm, const std::string &assetPath);
static void SetLoop(EcmaVM *vm, void *loop);
static std::string GetAssetPath(EcmaVM *vm);
static bool InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *data);
static bool InitForConcurrentFunction(EcmaVM *vm, Local<JSValueRef> func);
static void SetBundleName(EcmaVM *vm, std::string bundleName);
static std::string GetBundleName(EcmaVM *vm);

View File

@ -2699,6 +2699,13 @@ std::string JSNApi::GetAssetPath(EcmaVM *vm)
return vm->GetAssetPath().c_str();
}
bool JSNApi::InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *data)
{
vm->SetConcurrentCallback(cb, data);
return true;
}
bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local<JSValueRef> function)
{
[[maybe_unused]] LocalScope scope(vm);

View File

@ -1387,6 +1387,8 @@ JSHandle<JSFunction> ObjectFactory::NewJSFunction(const JSHandle<GlobalEnv> &env
hclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
} else if (JSFunction::IsConstructorKind(kind)) {
hclass = JSHandle<JSHClass>::Cast(env->GetConstructorFunctionClass());
} else if (kind == FunctionKind::CONCURRENT_FUNCTION) {
hclass = JSHandle<JSHClass>::Cast(env->GetAsyncFunctionClass());
} else {
hclass = JSHandle<JSHClass>::Cast(env->GetNormalFunctionClass());
}

View File

@ -1795,7 +1795,6 @@ JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandle<M
FunctionKind kind = methodHandle->GetFunctionKind();
switch (kind) {
case FunctionKind::NORMAL_FUNCTION:
case FunctionKind::CONCURRENT_FUNCTION:
case FunctionKind::BASE_CONSTRUCTOR: {
auto hclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
jsFunc = factory->NewJSFunctionByHClass(methodHandle, hclass);
@ -1811,6 +1810,7 @@ JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandle<M
jsFunc = factory->NewJSFunctionByHClass(methodHandle, generatorClass);
break;
}
case FunctionKind::CONCURRENT_FUNCTION:
case FunctionKind::ASYNC_FUNCTION: {
auto asyncClass = JSHandle<JSHClass>::Cast(env->GetAsyncFunctionClass());
jsFunc = factory->NewJSFunctionByHClass(methodHandle, asyncClass);

View File

@ -1553,7 +1553,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeFunction)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSFunction> jsFunction = factory->NewJSFunction(env);
JSHandle<JSFunction> jsFunction = factory->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION);
EXPECT_TRUE(jsFunction->IsJSFunction());
JSSerializer *serializer = new JSSerializer(thread);
@ -1571,9 +1571,9 @@ HWTEST_F_L0(JSSerializerTest, SerializeObjectWithFunction)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> function1 = env->GetFunctionFunction();
JSHandle<JSFunction> function1 = factory->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION);
EXPECT_TRUE(function1->IsJSFunction());
JSHandle<JSTaggedValue> function2 = env->GetFunctionFunction();
JSHandle<JSFunction> function2 = factory->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION);
EXPECT_TRUE(function2->IsJSFunction());
JSHandle<JSTaggedValue> key1(factory->NewFromASCII("1"));
JSHandle<JSTaggedValue> key2(factory->NewFromASCII("2"));
@ -1585,9 +1585,9 @@ HWTEST_F_L0(JSSerializerTest, SerializeObjectWithFunction)
JSHandle<JSTaggedValue> value3(factory->NewFromASCII("value"));
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key1, value1);
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key2, function1);
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key2, JSHandle<JSTaggedValue>(function1));
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key3, value2);
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key4, function2);
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key4, JSHandle<JSTaggedValue>(function2));
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), key5, value3);
JSSerializer *serializer = new JSSerializer(thread);