diff --git a/static_core/isa/isa.yaml b/static_core/isa/isa.yaml index 7753bff0281c83714dbfe6df43c0c81c55a0d2d0..e766e2f941191dbe2a36571ffe175920cedb0abd 100644 --- a/static_core/isa/isa.yaml +++ b/static_core/isa/isa.yaml @@ -3009,7 +3009,7 @@ groups: acc: out:ref format: [pref_op_v_8_id_32] prefix: any - opcode_idx: [0xa6] + opcode_idx: [0x0] - title: Get field from reference of any type by name description: > @@ -3036,7 +3036,7 @@ groups: acc: none format: [pref_op_v1_8_v2_8_id_32] prefix: any - opcode_idx: [0xa7] + opcode_idx: [0x1] - title: Store accumulator content into reference of any type field by name description: > @@ -3063,7 +3063,7 @@ groups: acc: in:ref format: [pref_op_v_8_id_32] prefix: any - opcode_idx: [0xa8] + opcode_idx: [0x2] - title: Store register content into reference of any type field by name description: > @@ -3076,21 +3076,21 @@ groups: exceptions: - x_null pseudo: | - if v2 == null then + if v1 == null then throw NullPointerException end - field = resolve_field_by_name(v2, string_id) + field = resolve_field_by_name(v1, string_id) if op == any.stbyname.v and size(field) < 32 then - v2.set(field, truncate(field, v1)) + v1.set(field, truncate(field, v2)) else - v2.set(field, v1) + v1.set(field, v2) end instructions: - sig: any.stbyname.v v1:in:ref, v2:in:ref, string_id acc: none format: [pref_op_v1_8_v2_8_id_32] prefix: any - opcode_idx: [0xa9] + opcode_idx: [0x3] - title: Load value to accumulator from reference of any type by index description: > @@ -3110,7 +3110,7 @@ groups: acc: inout:i32->ref format: [pref_op_v_8] prefix: any - opcode_idx: [0xaa] + opcode_idx: [0x4] - title: Store value from accumulator in reference of any type by index description: > @@ -3131,7 +3131,7 @@ groups: acc: in:ref format: [pref_op_v1_8_v2_8] prefix: any - opcode_idx: [0xab] + opcode_idx: [0x5] - title: Load value to accumulator from reference of any type by value description: > @@ -3151,7 +3151,7 @@ groups: acc: out:ref format: [pref_op_v1_8_v2_8] prefix: any - opcode_idx: [0xac] + opcode_idx: [0x6] - title: Store value from accumulator in reference of any type by value description: > @@ -3172,7 +3172,7 @@ groups: acc: in:ref format: [pref_op_v1_8_v2_8] prefix: any - opcode_idx: [0xad] + opcode_idx: [0x7] - title: Any call 0 description: > @@ -3190,7 +3190,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8] - opcode_idx: [0xae] + opcode_idx: [0x8] - title: Any call range description: > @@ -3210,7 +3210,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8_v2_8_imm_8_id_32] - opcode_idx: [0xaf] + opcode_idx: [0x9] - title: Any call short description: > @@ -3230,7 +3230,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_4_imm_4_id_32] - opcode_idx: [0xb0] + opcode_idx: [0xa] - title: Any call this 0 description: > @@ -3250,7 +3250,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8_id_32] - opcode_idx: [0xb1] + opcode_idx: [0xb] - title: Any call this range description: > @@ -3270,7 +3270,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8_v2_8_imm_8_id_32] - opcode_idx: [0xb2] + opcode_idx: [0xc] - title: Any call thils short description: > @@ -3290,7 +3290,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_4_imm_4_id_32] - opcode_idx: [0xb3] + opcode_idx: [0xd] - title: Any call new 0 description: > @@ -3308,7 +3308,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8] - opcode_idx: [0xb4] + opcode_idx: [0xe] - title: Any call new range description: > @@ -3326,7 +3326,7 @@ groups: acc: out:top prefix: any format: [pref_op_v1_8_v2_8_imm_8] - opcode_idx: [0xb5] + opcode_idx: [0xf] - title: Any call new short description: > @@ -3344,4 +3344,4 @@ groups: acc: out:top prefix: any format: [pref_op_v1_4_imm_4] - opcode_idx: [0xb6] + opcode_idx: [0x10] diff --git a/static_core/plugins/ets/runtime/ets_platform_types.cpp b/static_core/plugins/ets/runtime/ets_platform_types.cpp index f488200132cdbd0f2051ebdb49f3745496bb02f8..5390c45822d794f852b4061d15f5fd873581ae8c 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.cpp +++ b/static_core/plugins/ets/runtime/ets_platform_types.cpp @@ -181,6 +181,8 @@ EtsPlatformTypes::EtsPlatformTypes([[maybe_unused]] EtsCoroutine *coro) findMethod(&EtsPlatformTypes::escompatRecordSetter, escompatRecord, SET_INDEX_METHOD, nullptr, false); findType(&EtsPlatformTypes::interopJSValue, JS_VALUE); + EtsPlatformTypes::interopJSValue->GetRuntimeClass()->SetXRefClass(); + EtsPlatformTypes::interopJSValue->GetRuntimeClass()->SetXRefClass(); findType(&EtsPlatformTypes::coreField, FIELD); findType(&EtsPlatformTypes::coreMethod, METHOD); diff --git a/static_core/plugins/ets/runtime/ets_stubs-inl.h b/static_core/plugins/ets/runtime/ets_stubs-inl.h index 621d3326dd6006fa546f0da911b17e1d45462cc9..5b65bcf9e3dc333d01bf2c64511c04eb5e7bbb47 100644 --- a/static_core/plugins/ets/runtime/ets_stubs-inl.h +++ b/static_core/plugins/ets/runtime/ets_stubs-inl.h @@ -16,6 +16,7 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_STUBS_INL_H #define PANDA_PLUGINS_ETS_RUNTIME_STUBS_INL_H +#include "ets_stubs.h" #include "plugins/ets/runtime/ets_coroutine.h" #include "plugins/ets/runtime/types/ets_object.h" #include "plugins/ets/runtime/ets_stubs.h" @@ -418,7 +419,41 @@ ALWAYS_INLINE inline Method *GetMethodByName(EtsCoroutine *coro, ETSStubCacheInf } return callee; } +ALWAYS_INLINE inline ObjectHeader *PluginAnyLdbyval(ManagedThread *thread, ObjectHeader *thisObj, + ObjectHeader *key) +{ + return EtsLdByVal(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(thisObj), EtsObject::FromCoreType(key))->GetCoreType(); +} + +ALWAYS_INLINE inline ObjectHeader *PluginAnyLdbyidx(ManagedThread *thread, ObjectHeader *thisObj, + int32_t index) +{ + return EtsLdByIdx(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(thisObj), index)->GetCoreType(); +} + +ALWAYS_INLINE inline ObjectHeader *PluginAnyLdbyname(ManagedThread *thread, ObjectHeader *thisObj, + panda_file::File::StringData name) +{ + return EtsLdByName(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(thisObj), name)->GetCoreType(); +} +ALWAYS_INLINE inline void PluginAnyStbyval(ManagedThread *thread, ObjectHeader *obj, + ObjectHeader *key, ObjectHeader *val) +{ + EtsStByVal(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(obj), EtsObject::FromCoreType(key), EtsObject::FromCoreType(val)); +} + +ALWAYS_INLINE inline void PluginAnyStbyname(ManagedThread *thread, ObjectHeader *obj, + panda_file::File::StringData propName, ObjectHeader *val) +{ + EtsStByName(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(obj), propName, EtsObject::FromCoreType(val)); +} + +ALWAYS_INLINE inline void PluginAnyStbyidx(ManagedThread *thread, ObjectHeader *obj, + int32_t idx, ObjectHeader *val) +{ + EtsStByIdx(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(obj), idx, EtsObject::FromCoreType(val)); +} } // namespace ark::ets #endif // PANDA_PLUGINS_ETS_RUNTIME_STUBS_INL_H diff --git a/static_core/plugins/ets/runtime/ets_stubs.cpp b/static_core/plugins/ets/runtime/ets_stubs.cpp index c6c0ca47d383425ec8bb71567f6a52e2321c019e..b16e99452e75069681992e3beaddbd5196d33c7e 100644 --- a/static_core/plugins/ets/runtime/ets_stubs.cpp +++ b/static_core/plugins/ets/runtime/ets_stubs.cpp @@ -14,13 +14,24 @@ * limitations under the License. */ +#include "ets_stubs.h" #include "plugins/ets/runtime/ets_class_linker_extension.h" #include "plugins/ets/runtime/ets_stubs-inl.h" #include "plugins/ets/runtime/types/ets_box_primitive.h" #include "plugins/ets/runtime/types/ets_base_enum.h" #include "plugins/ets/runtime/types/ets_string.h" +#ifdef PANDA_ETS_INTEROP_JS +#include "plugins/ets/runtime/interop_js/intrinsics_api_impl.h" +#endif + namespace ark::ets { +#ifdef PANDA_ETS_INTEROP_JS +using JSValue = interop::js::JSValue; +using JSConvertEtsObject = interop::js::JSConvertEtsObject; +using JSConvertJSValue = interop::js::JSConvertJSValue; +using JSConvertString = interop::js::JSConvertString; +#endif template static std::optional GetBoxedNumericValue(EtsPlatformTypes const *ptypes, EtsObject *obj) @@ -250,4 +261,119 @@ bool EtsGetIstrue(EtsCoroutine *coro, EtsObject *obj) UNREACHABLE(); } +EtsObject *EtsLdByVal(EtsCoroutine *coro, EtsObject *thisObj, EtsObject *valObj) +{ + if (thisObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(thisObj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(thisObj); + if (valObj->IsStringClass()) { + return interop::js::JSValueNamedGetter(thisValue, EtsString::FromEtsObject(valObj)); + } else if (valObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { + return interop::js::GetPropertyObject(thisValue, JSValue::FromEtsObject(valObj)); + } + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), valObj); + if (unboxedValue.has_value()){ + return interop::js::JSValueIndexedGetter(thisValue, unboxedValue.value()); + } + LOG(ERROR, RUNTIME) << "input value cannot be casted to valid property key"; + return nullptr; +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} + +EtsObject *EtsLdByIdx(EtsCoroutine *coro, EtsObject *thisObj, int32_t index) +{ + if (thisObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(thisObj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(thisObj); + return interop::js::JSValueIndexedGetter(thisValue, index); +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} + +EtsObject *EtsLdByName(EtsCoroutine *coro, EtsObject *thisObj, panda_file::File::StringData name) +{ + if (thisObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(thisObj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(thisObj); + return interop::js::GetNamedPropertyObject(thisValue, utf::Mutf8AsCString(name.data)); + // return interop::js::GetPropertyJSValueByString(thisValue, utf::Mutf8AsCString(name.data)) +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} + +void EtsStByVal(EtsCoroutine *coro, EtsObject *obj, EtsObject *key, EtsObject *value) +{ + // JSValueNamedSetter(etsJsValue, etsPropName, value); + if (obj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(obj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(obj); + if (key->IsStringClass()) { + interop::js::SetNamedPropertyWithObject(thisValue, utf::Mutf8AsCString(EtsString::FromEtsObject(key)->GetDataMUtf8()), value); + } else if (key->GetClass()->GetRuntimeClass()->IsXRefClass()) { + interop::js::SetPropertyWithObject(thisValue, JSValue::FromEtsObject(key), value); + } + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), key); // zzm: buggy here + if (unboxedValue.has_value()){ + interop::js::SetIndexedPropertyWithObject(thisValue, unboxedValue.value(), value); + } +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return; + } +} + +void EtsStByName(EtsCoroutine *coro, EtsObject *obj, panda_file::File::StringData propName, EtsObject *value) +{ + if (obj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(obj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(obj); + interop::js::SetNamedPropertyWithObject(thisValue, utf::Mutf8AsCString(propName.data), value); +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return; + } +} + +void EtsStByIdx(EtsCoroutine *coro, EtsObject *obj, int32_t idx, EtsObject *value) +{ + if (obj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + ASSERT(obj->GetClass() == PlatformTypes(coro)->interopJSValue); + auto thisValue = JSValue::FromEtsObject(obj); + interop::js::SetIndexedPropertyWithObject(thisValue, idx, value); +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + return; + } +} } // namespace ark::ets diff --git a/static_core/plugins/ets/runtime/ets_stubs.h b/static_core/plugins/ets/runtime/ets_stubs.h index 13481ce71332b1cf6adabb03b78d166da449432a..3cd29205c7318255f6cd0bc05b5355d7d7a55a13 100644 --- a/static_core/plugins/ets/runtime/ets_stubs.h +++ b/static_core/plugins/ets/runtime/ets_stubs.h @@ -47,6 +47,18 @@ EtsString *EtsGetTypeof(EtsCoroutine *coro, EtsObject *obj); bool EtsGetIstrue(EtsCoroutine *coro, EtsObject *obj); +EtsObject *EtsLdByVal(EtsCoroutine *coro, EtsObject *thisObj, EtsObject *valObj); + +EtsObject *EtsLdByIdx(EtsCoroutine *coro, EtsObject *thisObj, int32_t idx); + +EtsObject *EtsLdByName(EtsCoroutine *coro, EtsObject *thisObj, panda_file::File::StringData name); + +void EtsStByVal(EtsCoroutine *coro, EtsObject *obj, EtsObject *valObj, EtsObject *value); + +void EtsStByName(EtsCoroutine *coro, EtsObject *obj, panda_file::File::StringData propName, EtsObject *value); + +void EtsStByIdx(EtsCoroutine *coro, EtsObject *obj, int32_t idx, EtsObject *value); + template inline void LookUpException(ark::Class *klass, Field *rawField); diff --git a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp index 824b87898d8cc5d08184a30bd619a5e5d3aca875..a0f4b9acfbd64cf19af31914f8e294d72379467d 100644 --- a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp +++ b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.cpp @@ -516,6 +516,19 @@ uint8_t JSRuntimeHasProperty(JSValue *object, EtsString *name) return static_cast(result); } +static napi_value JSRuntimeGetPropertyImpl(EtsCoroutine *coro, napi_env env, JSValue *object, JSValue *property) +{ + auto jsThis = JSConvertJSValue::WrapWithNullCheck(env, object); + auto key = JSConvertJSValue::WrapWithNullCheck(env, property); + + napi_value result; + { + ScopedNativeCodeThread nativeScope(coro); + NAPI_CHECK_FATAL(napi_get_property(env, jsThis, key, &result)); + } + return result; +} + JSValue *JSRuntimeGetProperty(JSValue *object, JSValue *property) { auto coro = EtsCoroutine::GetCurrent(); @@ -524,15 +537,130 @@ JSValue *JSRuntimeGetProperty(JSValue *object, JSValue *property) auto env = ctx->GetJSEnv(); NapiScope jsHandleScope(env); + auto result = JSRuntimeGetPropertyImpl(coro, env, object, property); + return JSConvertJSValue::UnwrapWithNullCheck(ctx, env, result).value(); +} + +void SetPropertyWithObject(JSValue *object, JSValue *property, EtsObject *value) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + auto jsThis = JSConvertJSValue::WrapWithNullCheck(env, object); auto key = JSConvertJSValue::WrapWithNullCheck(env, property); + auto jsValue = JSRefConvertResolve(ctx, value->GetClass()->GetRuntimeClass())->Wrap(ctx, value); - napi_value result; { ScopedNativeCodeThread nativeScope(coro); - NAPI_CHECK_FATAL(napi_get_property(env, jsThis, key, &result)); + NAPI_CHECK_FATAL(napi_set_property(env, jsThis, key, jsValue)); } - return JSConvertJSValue::UnwrapWithNullCheck(ctx, env, result).value(); + return; +} + +void SetIndexedPropertyWithObject(JSValue *object, uint32_t index, EtsObject *value) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + auto jsThis = JSConvertJSValue::WrapWithNullCheck(env, object); + auto jsValue = JSRefConvertResolve(ctx, value->GetClass()->GetRuntimeClass())->Wrap(ctx, value); + + { + ScopedNativeCodeThread nativeScope(coro); + NAPI_CHECK_FATAL(napi_set_element(env, jsThis, index, jsValue)); + } + return; +} + +void SetNamedPropertyWithObject(JSValue *object, const char *key, EtsObject *value) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + auto jsThis = JSConvertJSValue::WrapWithNullCheck(env, object); + auto jsValue = JSRefConvertResolve(ctx, value->GetClass()->GetRuntimeClass())->Wrap(ctx, value); + + { + ScopedNativeCodeThread nativeScope(coro); + NAPI_CHECK_FATAL(napi_set_named_property(env, jsThis, key, jsValue)); + } + return; +} + + +EtsObject *GetPropertyObject(JSValue *object, JSValue *property) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + auto result = JSRuntimeGetPropertyImpl(coro, env, object, property); + return JSConvertEtsObject::UnwrapWithNullCheck(ctx, env, result).value(); +} + +EtsObject *GetNamedPropertyObject(JSValue *object, const char *property) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + return JSValueGetByName(ctx, object, property).value(); +} + +JSValue *GetNamedPropertyJSValue(JSValue *object, const char *property) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + return JSValueGetByName(ctx, object, property).value(); +} + +EtsObject *InvokeWithObjectReturn(JSValue *recv, JSValue *func, Span args) +{ + auto coro = EtsCoroutine::GetCurrent(); + auto ctx = InteropCtx::Current(coro); + INTEROP_CODE_SCOPE_ETS(coro); + auto env = ctx->GetJSEnv(); + NapiScope jsHandleScope(env); + + PandaVector realArgs; + + for (size_t i = 0; i < args.size(); i++) { + EtsObject *arg = EtsObject::FromCoreType(args[i]); + auto realArg = ctx->GetEtsClassWrappersCache()->Lookup(arg->GetClass())->Wrap(ctx, arg); + realArgs.push_back(realArg); + } + + napi_value retVal; + napi_status jsStatus; + auto recvEtsObject = JSConvertJSValue::WrapWithNullCheck(env, recv); + auto funcEtsObject = JSConvertJSValue::WrapWithNullCheck(env, func); + { + ScopedNativeCodeThread nativeScope(coro); + jsStatus = napi_call_function(env, recvEtsObject, funcEtsObject, realArgs.size(), realArgs.data(), &retVal); + } + + if (jsStatus != napi_ok) { + ctx->ForwardJSException(coro); + return nullptr; + } + return JSConvertEtsObject::UnwrapWithNullCheck(ctx, env, retVal).value(); } uint8_t JSRuntimeHasPropertyJSValue(JSValue *object, JSValue *property) diff --git a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h index b7bb49a8dbc155e02c248a6e4e764b8bb3178048..91b1da42a2397d3814f934acfdb8c9ed7c3ee6f3 100644 --- a/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h +++ b/static_core/plugins/ets/runtime/interop_js/intrinsics_api_impl.h @@ -60,6 +60,13 @@ JSValue *JSRuntimeInvoke(JSValue *recv, JSValue *func, EtsArray *args); JSValue *JSRuntimeInstantiate(JSValue *callable, EtsArray *args); EtsString *JSValueToString(JSValue *object); napi_value ToLocal(void *value); +void SetPropertyWithObject(JSValue *object, JSValue *property, EtsObject *value); +void SetIndexedPropertyWithObject(JSValue *object, uint32_t index, EtsObject *value); +void SetNamedPropertyWithObject(JSValue *object, const char *val, EtsObject *value); +EtsObject *GetPropertyObject(JSValue *object, JSValue *property); +EtsObject *GetNamedPropertyObject(JSValue *object, const char *property); +JSValue *GetNamedPropertyJSValue(JSValue *object, const char *property); +EtsObject *InvokeWithObjectReturn(JSValue *thisObj, JSValue *function, Span args); void *CompilerGetJSNamedProperty(void *val, char *propStr); void *CompilerGetJSProperty(void *val, void *prop); void *CompilerGetJSElement(void *val, int32_t index); @@ -166,7 +173,7 @@ void JSValueIndexedSetter(JSValue *etsJsValue, int32_t index, typename T::cpptyp NapiScope jsHandleScope(env); auto rec = napi_set_element(env, JSConvertJSValue::WrapWithNullCheck(env, etsJsValue), index, - JSConvertJSValue::WrapWithNullCheck(env, value)); + T::WrapWithNullCheck(env, value)); if (rec != napi_ok) { ctx->ForwardJSException(coro); } diff --git a/static_core/plugins/ets/runtime/interop_js/js_convert.h b/static_core/plugins/ets/runtime/interop_js/js_convert.h index 4b2250bb7f67ddbb8f45e9429a8826108abd3d62..9e8603169da1f13f7a5d70b1493b95c8d44762d3 100644 --- a/static_core/plugins/ets/runtime/interop_js/js_convert.h +++ b/static_core/plugins/ets/runtime/interop_js/js_convert.h @@ -242,6 +242,19 @@ JSCONVERT_UNWRAP(JSValue) return JSValue::Create(EtsCoroutine::GetCurrent(), ctx, jsVal); } +// NOTE(zhaoziming_hw, #xxxx) workaround for no converter based on JS source type +JSCONVERT_DEFINE_TYPE(EtsObject, EtsObject *); +JSCONVERT_WRAP(EtsObject) +{ + InteropFatal("Wrap of EtsObject should be done with relevant converter"); + UNREACHABLE(); +} +JSCONVERT_UNWRAP(EtsObject) +{ + auto objectConverter = ctx->GetEtsClassWrappersCache()->Lookup(PlatformTypes()->coreObject); + return objectConverter->Unwrap(ctx, jsVal); +} + // ESError convertors are supposed to box JSValue objects, do not treat them in any other way JSCONVERT_DEFINE_TYPE(ESError, EtsObject *); JSCONVERT_WRAP(ESError) @@ -388,7 +401,7 @@ JSCONVERT_UNWRAP(EtsNull) #undef JSCONVERT_UNWRAP template -static ALWAYS_INLINE inline std::optional JSValueGetByName(InteropCtx *ctx, JSValue *jsvalue, +ALWAYS_INLINE inline std::optional JSValueGetByName(InteropCtx *ctx, JSValue *jsvalue, const char *name) { auto env = ctx->GetJSEnv(); @@ -405,7 +418,7 @@ static ALWAYS_INLINE inline std::optional JSValueGetByName( } template -[[nodiscard]] static ALWAYS_INLINE inline bool JSValueSetByName(InteropCtx *ctx, JSValue *jsvalue, const char *name, +[[nodiscard]] ALWAYS_INLINE inline bool JSValueSetByName(InteropCtx *ctx, JSValue *jsvalue, const char *name, typename T::cpptype etsPropVal) { auto env = ctx->GetJSEnv(); diff --git a/static_core/plugins/ets/runtime/types/ets_string.h b/static_core/plugins/ets/runtime/types/ets_string.h index 51569768461efa392058aff050e804fe5c12771f..f192da961caaee96321ca25289dbc2e1b29befb4 100644 --- a/static_core/plugins/ets/runtime/types/ets_string.h +++ b/static_core/plugins/ets/runtime/types/ets_string.h @@ -16,13 +16,15 @@ #ifndef PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_ #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_STRING_H_ -#include "runtime/include/runtime.h" -#include "runtime/include/coretypes/string-inl.h" +#include + +#include "libpandabase/utils/utf.h" #include "plugins/ets/runtime/types/ets_array.h" #include "plugins/ets/runtime/types/ets_box_primitive.h" #include "plugins/ets/runtime/types/ets_object.h" #include "plugins/ets/runtime/napi/ets_napi.h" -#include +#include "runtime/include/runtime.h" +#include "runtime/include/coretypes/string-inl.h" namespace ark::ets { diff --git a/static_core/runtime/include/class.h b/static_core/runtime/include/class.h index a6121da5975ae474ead8522102d18625d9b97725..d2ff358a076c7e5581f2c495644b46e888244189 100644 --- a/static_core/runtime/include/class.h +++ b/static_core/runtime/include/class.h @@ -121,6 +121,7 @@ public: using UniqId = uint64_t; static constexpr uint32_t STRING_CLASS = DYNAMIC_CLASS << 1U; static constexpr uint32_t IS_CLONEABLE = STRING_CLASS << 1U; + static constexpr uint32_t XREF_CLASS = IS_CLONEABLE << 1U; static constexpr size_t IMTABLE_SIZE = 32; enum { @@ -355,6 +356,11 @@ public: return (GetFlags() & STRING_CLASS) != 0; } + bool IsXRefClass() const + { + return (GetFlags() & XREF_CLASS) != 0; + } + void SetStringClass() { SetFlags(GetFlags() | STRING_CLASS); @@ -365,6 +371,11 @@ public: SetFlags(GetFlags() | IS_CLONEABLE); } + void SetXRefClass() + { + SetFlags(GetFlags() | XREF_CLASS); + } + bool IsVariableSize() const { return IsArrayClass() || IsStringClass(); diff --git a/static_core/runtime/interpreter/interpreter-inl.h b/static_core/runtime/interpreter/interpreter-inl.h index a93af873b73936ca55e2de9f5a0c1d3320d9901e..d8db2a774eaad1f9a3517f7a30fc2a7cf0140fdf 100644 --- a/static_core/runtime/interpreter/interpreter-inl.h +++ b/static_core/runtime/interpreter/interpreter-inl.h @@ -59,6 +59,9 @@ #include "runtime/mem/vm_handle.h" #include "runtime/handle_base-inl.h" +#include "plugins/ets/runtime/ets_stubs.h" +#include "plugins/ets/runtime/ets_stubs-inl.h" + // ALWAYS_INLINE is mandatory attribute for handlers. There are cases which will be failed without it. namespace ark::interpreter { @@ -3855,8 +3858,19 @@ public: this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto ldObj = ets::PluginAnyLdbyname(this->GetThread(), obj, pf->GetStringData(id.AsFileId())); + if (UNLIKELY(ldObj == nullptr)) { + RuntimeIfaceT::ThrowNullPointerException(); + this->MoveToExceptionHandler(); + }else { + this->GetAccAsVReg().SetReference(ldObj); + } + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3874,8 +3888,19 @@ public: this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto ldObj = ets::PluginAnyLdbyname(this->GetThread(), obj, pf->GetStringData(id.AsFileId())); + if (UNLIKELY(ldObj == nullptr)) { + RuntimeIfaceT::ThrowNullPointerException(); + this->MoveToExceptionHandler(); + }else { + this->GetFrameHandler().GetVReg(vd).SetReference(ldObj); + } + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3887,13 +3912,20 @@ public: LOG_INST() << "any.stbyname v" << vs << ", " << std::hex << "0x" << id; ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference(); - if (UNLIKELY(obj == nullptr)) { + ObjectHeader *value = this->GetAccAsVReg().GetReference(); + if (UNLIKELY(obj == nullptr || value == nullptr)) { RuntimeIfaceT::ThrowNullPointerException(); this->MoveToExceptionHandler(); + UNREACHABLE(); } - - // NOTE: handle it - UNREACHABLE(); + + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + ets::PluginAnyStbyname(this->GetThread(), obj, pf->GetStringData(id.AsFileId()), value); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3905,14 +3937,21 @@ public: LOG_INST() << "any.stbyname.v v" << vs1 << ", v" << vs2 << ", " << std::hex << "0x" << id; - ObjectHeader *obj = this->GetFrame()->GetVReg(vs2).GetReference(); - if (UNLIKELY(obj == nullptr)) { + ObjectHeader *obj = this->GetFrame()->GetVReg(vs1).GetReference(); + ObjectHeader *val = this->GetFrame()->GetVReg(vs2).GetReference(); + if (UNLIKELY(obj == nullptr || val == nullptr)) { RuntimeIfaceT::ThrowNullPointerException(); this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + ets::PluginAnyStbyname(this->GetThread(), obj, + pf->GetStringData(id.AsFileId()), val); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3923,13 +3962,25 @@ public: LOG_INST() << "any.ldbyidx v" << vs << ", " << std::hex; ObjectHeader *obj = this->GetFrame()->GetVReg(vs).GetReference(); + ASSERT(!this->GetFrame()->GetAccAsVReg().HasObject()); + int32_t index = this->GetAccAsVReg().Get(); + if (UNLIKELY(obj == nullptr)) { RuntimeIfaceT::ThrowNullPointerException(); this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto ldObj = ets::PluginAnyLdbyidx(this->GetThread(), obj, index); + if (UNLIKELY(ldObj == nullptr)) { + RuntimeIfaceT::ThrowNullPointerException(); + this->MoveToExceptionHandler(); + } + this->GetAccAsVReg().SetReference(ldObj); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3938,16 +3989,22 @@ public: uint16_t vs1 = this->GetInst().template GetVReg(); uint16_t vs2 = this->GetInst().template GetVReg(); - LOG_INST() << "any.stbyidx v" << vs1 << ", v" << vs2 << ", " << std::hex; + LOG_INST() << "any.stbyidx v" << vs1 << ", " << vs2 << std::hex; ObjectHeader *obj = this->GetFrame()->GetVReg(vs1).GetReference(); - if (UNLIKELY(obj == nullptr)) { + int32_t index = this->GetFrame()->GetVReg(vs2).Get(); + ObjectHeader *val = this->GetAccAsVReg().GetReference(); + if (UNLIKELY(obj == nullptr || val == nullptr)) { RuntimeIfaceT::ThrowNullPointerException(); this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + ets::PluginAnyStbyidx(this->GetThread(), obj, index, val); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3965,8 +4022,17 @@ public: this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto ldObj = ets::PluginAnyLdbyval(this->GetThread(), obj, valObj); + if (UNLIKELY(ldObj == nullptr)) { + RuntimeIfaceT::ThrowNullPointerException(); + this->MoveToExceptionHandler(); + } + this->GetAccAsVReg().SetReference(ldObj); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } template @@ -3979,13 +4045,18 @@ public: ObjectHeader *obj = this->GetFrame()->GetVReg(vs1).GetReference(); ObjectHeader *valObj = this->GetFrame()->GetVReg(vs2).GetReference(); - if (UNLIKELY(obj == nullptr || valObj == nullptr)) { + ObjectHeader *val = this->GetAccAsVReg().GetReference(); + if (UNLIKELY((obj == nullptr || valObj == nullptr) || val == nullptr)) { RuntimeIfaceT::ThrowNullPointerException(); this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + if (obj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + ets::PluginAnyStbyval(this->GetThread(), obj, valObj, val); + } else { + UNREACHABLE(); + } + this->template MoveToNextInst(); } private: @@ -4001,7 +4072,7 @@ private: { ObjectHeader *obj = nullptr; if constexpr (ACCEPT_ACC) { - if (this->GetInst().template GetImm() == 0) { + if (this->GetInst().template GetImm() == 0) { // imm obj = this->GetAcc().GetReference(); } else { obj = GetObjHelper();