diff --git a/static_core/compiler/optimizer/ir_builder/inst_builder-inl.h b/static_core/compiler/optimizer/ir_builder/inst_builder-inl.h index 95b5b029f08d716a44d7644c16685755933e6458..0d9461c65ecbff6816dec8b9a1dd1b46e418d273 100644 --- a/static_core/compiler/optimizer/ir_builder/inst_builder-inl.h +++ b/static_core/compiler/optimizer/ir_builder/inst_builder-inl.h @@ -1682,6 +1682,14 @@ void InstBuilder::BuildAnyCall([[maybe_unused]] const BytecodeInstruction *bcIns UNREACHABLE(); } +// NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers) +void InstBuilder::BuildIsInstanceAny([[maybe_unused]] const BytecodeInstruction *bcInst, + [[maybe_unused]] DataType::Type type) +{ + // NOTE: handle it + UNREACHABLE(); +} + } // namespace ark::compiler #endif // PANDA_INST_BUILDER_INL_H diff --git a/static_core/compiler/optimizer/ir_builder/inst_builder.h b/static_core/compiler/optimizer/ir_builder/inst_builder.h index 07f93de26c15c902f97dd876128a01dac3ae3763..86f044787e346c51667f2999e3dbd8dfa7af50fc 100644 --- a/static_core/compiler/optimizer/ir_builder/inst_builder.h +++ b/static_core/compiler/optimizer/ir_builder/inst_builder.h @@ -389,6 +389,7 @@ private: void BuildStoreFromAnyByIdx(const BytecodeInstruction *bcInst, DataType::Type type); void BuildLoadFromAnyByVal(const BytecodeInstruction *bcInst, DataType::Type type); void BuildStoreFromAnyByVal(const BytecodeInstruction *bcInst, DataType::Type type); + void BuildIsInstanceAny(const BytecodeInstruction *bcInst, DataType::Type type); template void BuildAnyCall(const BytecodeInstruction *bcInst); diff --git a/static_core/compiler/optimizer/ir_builder/inst_templates.yaml b/static_core/compiler/optimizer/ir_builder/inst_templates.yaml index 06e540de1aeaf4f52c71d26202e6a1e1bf44d171..314a8418f1e7567fb24bab0734246f9b9eaa2112 100644 --- a/static_core/compiler/optimizer/ir_builder/inst_templates.yaml +++ b/static_core/compiler/optimizer/ir_builder/inst_templates.yaml @@ -322,6 +322,8 @@ templates: BuildLoadFromAnyByVal(instruction, <%= get_type(inst.dtype) %>); % when "stbyval" BuildStoreFromAnyByVal(instruction, <%= get_type(inst.type(0)) %>); + % when "isinstance" + BuildIsInstanceAny(instruction, <%= get_type(inst.dtype) %>); % else UNREACHABLE(); % end diff --git a/static_core/compiler/optimizer/templates/inst_builder_gen.cpp.erb b/static_core/compiler/optimizer/templates/inst_builder_gen.cpp.erb index 49e099a93b221d0b897ee92021111e941baed198..9719efc1f0757a149f23bdcd54d91225aed42401 100644 --- a/static_core/compiler/optimizer/templates/inst_builder_gen.cpp.erb +++ b/static_core/compiler/optimizer/templates/inst_builder_gen.cpp.erb @@ -118,7 +118,7 @@ end /^monitor/ => "monitor", /^nop/ => "nop", /^builtin/ => "builtin", - /^any?$/ => "any", + /^any?$/ => "unimplemented", /^$/ => "unimplemented" } Panda::prefixes.select{|p| !p.public?}.each do |p| @@ -206,7 +206,8 @@ bool IrBuilderInliningAnalysis::IsSuitableForInline(const BytecodeInstruction* i switch(inst->GetOpcode()) { % runtime_insts = [/^(div|mod)u?[2i]?/, /^call/, /(ld|st|len|new)(arr|obj)/, /throw/, /^initobj/, /^checkcast/, /^ldstatic/, /^ststatic/, /^lda.type/, /^lda.str/, /^lda.const/, /^isinstance/, /^builtin/, % /^monitor/, -% /^ets.typeof/, /^ets.call.name/, /^ets.nullcheck/ +% /^ets.typeof/, /^ets.call.name/, /^ets.nullcheck/, +% /^any*/ % ] % Panda::instructions.each do |inst| // NOLINTNEXTLINE(bugprone-branch-clone) diff --git a/static_core/irtoc/scripts/interpreter.irt b/static_core/irtoc/scripts/interpreter.irt index 6719fa660f7d402e8a5ce413d3e920a78e358705..580b33bef3815ed1f25d1ad72c0322da05bf244d 100644 --- a/static_core/irtoc/scripts/interpreter.irt +++ b/static_core/irtoc/scripts/interpreter.irt @@ -2094,44 +2094,75 @@ include_plugin 'interpreter_handlers' # Any type support macro(:handle_any_ldbyname_v8_id32) do |vs, id| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + set_acc_object(call_runtime("AnyLdByNameEntrypoint", %tr, %frame, vs, id).ref) end macro(:handle_any_ldbyname_v_v8_v8_id32) do |vd, vs, id| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + set_object(vd, call_runtime("AnyLdByNameEntrypoint", %tr, %frame, vs, id).ref).ref end macro(:handle_any_stbyname_v8_id32) do |vs, id| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + call_runtime("AnyStByNameEntrypoint", %tr, %frame, vs, id, acc.ref).void end macro(:handle_any_stbyname_v_v8_v8_id32) do |vs1, vs2, id| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + call_runtime("AnyStByNameEntrypoint", %tr, %frame, vs2, id, vs1).void end macro(:handle_any_ldbyidx_v8) do |vs| - # NOTE: handle it - set_acc_object(vs) # NOTE: fixes build for ARK_HYBRID - Intrinsic(:UNREACHABLE).Terminator.void + set_acc_object(call_runtime("AnyLdByIdxEntrypoint", %tr, vs, acc.i32).ref) end macro(:handle_any_stbyidx_v8_v8) do |vs1, vs2| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + call_runtime("AnyStByIdxEntrypoint", %tr, vs1, vs2, acc.ref).void end macro(:handle_any_ldbyval_v8_v8) do |vs1, vs2| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + set_acc_object(call_runtime("AnyLdByValEntrypoint", %tr, vs1, vs2).ref) end macro(:handle_any_stbyval_v8_v8) do |vs1, vs2| - # NOTE: handle it - Intrinsic(:UNREACHABLE).Terminator.void + set_acc_object(call_runtime("AnyStByValEntrypoint", %tr, vs1, vs2, acc.ref).ref) +end + +macro(:handle_any_isinstance_v8) do |vs| + set_acc_primitive(btou8(call_runtime("AnyIsInstanceEntrypoint", %tr, acc.ref, vs).b)) +end + +macro(:handle_any_call_0_v8) do |vs| + set_acc_object(call_runtime("AnyCall0Entrypoint", %tr, vs).ref) +end + +macro(:handle_any_call_short_v4_v4) do |vs1, vs2| + set_acc_object(call_runtime("AnyCallShortEntrypoint", %tr, vs1, vs2).ref) +end + +macro(:handle_any_call_range_v8_v8_imm8) do |vs1, first_arg, argc| + set_acc_object(call_runtime("AnyCallRangeEntrypoint", %tr, %frame, vs1, first_arg, argc).ref) +end + +macro(:handle_any_call_this_0_v8_id32) do |vs, id| + set_acc_object(call_runtime("AnyCallThis0Entrypoint", %tr, %frame, vs, id).ref) +end + +macro(:handle_any_call_this_short_v4_v4_id32) do |vs1, vs2, id| + set_acc_object(call_runtime("AnyCallThisShortEntrypoint", %tr, %frame, vs1, id, vs2).ref) +end + +macro(:handle_any_call_this_range_v8_v8_imm8_id32) do |vs1, first_arg, argc, id| + set_acc_object(call_runtime("AnyCallThisRangeEntrypoint", %tr, %frame, vs1, id, first_arg, argc).ref) +end + +macro(:handle_any_call_new_0_v8) do |vs| + set_acc_object(call_runtime("AnyCallNew0Entrypoint", %tr, vs).ref) +end + +macro(:handle_any_call_new_short_v4_v4) do |vs1, vs2| + set_acc_object(call_runtime("AnyCallNewShortEntrypoint", %tr, vs1, vs2).ref) +end + +macro(:handle_any_call_new_range_v8_v8_imm8) do |vs1, first_arg, argc| + set_acc_object(call_runtime("AnyCallNewRangeEntrypoint", %tr, %frame, vs1, first_arg, argc).ref) end # Functions: @@ -2925,11 +2956,11 @@ Panda.instructions.each do |i| # any type support when "ANY_LDBYNAME_PREF_V8_ID32" handle_any_ldbyname_v8_id32(vreg_value(op[0]).ref, as_id(op[1])) - when "ANY_LDBYNAME_PREF_V8_V8_ID32" - handle_any_ldbyname_v_v8_v8_id32(vreg_value(op[0]).ref, vreg_value(op[1]).ref, as_id(op[2])) + when "ANY_LDBYNAME_V_PREF_V8_V8_ID32" + handle_any_ldbyname_v_v8_v8_id32(vreg_ptr(op[0]), vreg_value(op[1]).ref, as_id(op[2])) when "ANY_STBYNAME_PREF_V8_ID32" handle_any_stbyname_v8_id32(vreg_value(op[0]).ref, as_id(op[1])) - when "ANY_STBYNAME_PREF_V8_V8_ID32" + when "ANY_STBYNAME_V_PREF_V8_V8_ID32" handle_any_stbyname_v_v8_v8_id32(vreg_value(op[0]).ref, vreg_value(op[1]).ref, as_id(op[2])) when "ANY_LDBYIDX_PREF_V8" handle_any_ldbyidx_v8(vreg_value(op[0]).ref) @@ -2939,6 +2970,26 @@ Panda.instructions.each do |i| handle_any_ldbyval_v8_v8(vreg_value(op[0]).ref, vreg_value(op[1]).ref) when "ANY_STBYVAL_PREF_V8_V8" handle_any_stbyval_v8_v8(vreg_value(op[0]).ref, vreg_value(op[1]).ref) + when "ANY_ISINSTANCE_PREF_V8" + handle_any_isinstance_v8(vreg_value(op[0]).ref) + when "ANY_CALL_0_PREF_V8" + handle_any_call_0_v8(vreg_value(op[0]).ref) + when "ANY_CALL_SHORT_PREF_V4_V4" + handle_any_call_short_v4_v4(vreg_value(op[0]).ref, vreg_value(op[1]).ref) + when "ANY_CALL_RANGE_PREF_V8_V8_IMM8" + handle_any_call_range_v8_v8_imm8(vreg_value(op[0]).ref, as_vreg_idx(op[1]).u8, as_imm(op[2]).u8) + when "ANY_CALL_THIS_0_PREF_V8_ID32" + handle_any_call_this_0_v8_id32(vreg_value(op[1]).ref, as_id(op[0])) + when "ANY_CALL_THIS_SHORT_PREF_V4_V4_ID32" + handle_any_call_this_short_v4_v4_id32(vreg_value(op[1]).ref, vreg_value(op[2]).ref, as_id(op[0])) + when "ANY_CALL_THIS_RANGE_PREF_V8_V8_IMM8_ID32" + handle_any_call_this_range_v8_v8_imm8_id32(vreg_value(op[1]).ref, as_vreg_idx(op[2]).u8, as_imm(op[3]).u8, as_id(op[0])) + when "ANY_CALL_NEW_0_PREF_V8" + handle_any_call_new_0_v8(vreg_value(op[0]).ref) + when "ANY_CALL_NEW_SHORT_PREF_V4_V4" + handle_any_call_new_short_v4_v4(vreg_value(op[0]).ref, vreg_value(op[1]).ref) + when "ANY_CALL_NEW_RANGE_PREF_V8_V8_IMM8" + handle_any_call_new_range_v8_v8_imm8(vreg_value(op[0]).ref, as_vreg_idx(op[1]).u8, as_imm(op[2]).u8) include_plugin 'interpreter_main_loop' diff --git a/static_core/isa/isa.yaml b/static_core/isa/isa.yaml index 7753bff0281c83714dbfe6df43c0c81c55a0d2d0..0dca873667ca2163f3e1eddc5ae14c815593f5ac 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: > @@ -3199,18 +3199,16 @@ groups: - compatible_arguments properties: - any_call - - string_id - - id_shift exceptions: - x_call pseudo: | TBD instructions: - - sig: any.call.range string_id, v1:in:top, v2:in:top, imm:u8 + - sig: any.call.range v1:in:top, v2:in:top, imm:u8 acc: out:top prefix: any - format: [pref_op_v1_8_v2_8_imm_8_id_32] - opcode_idx: [0xaf] + format: [pref_op_v1_8_v2_8_imm_8] + opcode_idx: [0x9] - title: Any call short description: > @@ -3219,18 +3217,16 @@ groups: - compatible_arguments properties: - any_call - - string_id - - id_shift exceptions: - x_call pseudo: | TBD instructions: - - sig: any.call.short string_id, v1:in:top, imm:u4 + - sig: any.call.short v1:in:top, v2:in:top acc: out:top prefix: any - format: [pref_op_v1_4_imm_4_id_32] - opcode_idx: [0xb0] + format: [pref_op_v1_4_v2_4] + opcode_idx: [0xa] - title: Any call this 0 description: > @@ -3250,7 +3246,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,9 +3266,9 @@ 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 + - title: Any call this short description: > TBD verification: @@ -3286,11 +3282,11 @@ groups: pseudo: | TBD instructions: - - sig: any.call.this.short string_id, v1:in:top, imm:u4 + - sig: any.call.this.short string_id, v1:in:top, v2:in:top acc: out:top prefix: any - format: [pref_op_v1_4_imm_4_id_32] - opcode_idx: [0xb3] + format: [pref_op_v1_4_v2_4_id_32] + opcode_idx: [0xd] - title: Any call new 0 description: > @@ -3308,7 +3304,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 +3322,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: > @@ -3340,8 +3336,24 @@ groups: pseudo: | TBD instructions: - - sig: any.call.new.short v1:in:top, imm:u4 + - sig: any.call.new.short v1:in:top, v2:in:top acc: out:top prefix: any - format: [pref_op_v1_4_imm_4] - opcode_idx: [0xb6] + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x10] + + - title: Any instanceof check + description: > + TBD + verification: + - v1_object + exceptions: + - x_null + pseudo: | + TBD + instructions: + - sig: any.isinstance v1:in:top + acc: inout:top->u1 + prefix: any + format: [pref_op_v1_8] + opcode_idx: [0x11] diff --git a/static_core/libllvmbackend/lowering/irtoc_function_utils.cpp b/static_core/libllvmbackend/lowering/irtoc_function_utils.cpp index dcf28160c499da0fc537e7b0a201eac78915ea1d..05ae0635cf2acd3c845f7de7627daa0b09359dbf 100644 --- a/static_core/libllvmbackend/lowering/irtoc_function_utils.cpp +++ b/static_core/libllvmbackend/lowering/irtoc_function_utils.cpp @@ -23,7 +23,13 @@ using namespace std::literals::string_view_literals; // Enables 'sv' suffix constexpr std::array NOALIAS_IRTOC_FUNC = { "CreateObjectByIdEntrypoint"sv, "CreateObjectByClassInterpreter"sv, "CreateArrayByIdEntrypoint"sv, - "CreateMultiDimensionalArrayById"sv, + "CreateMultiDimensionalArrayById"sv, "AnyLdByNameEntrypoint"sv, "AnyLdByNameEntrypoint"sv, + "AnyStByNameEntrypoint"sv, "AnyStByNameEntrypoint"sv, "AnyLdByIdxEntrypoint"sv, + "AnyStByIdxEntrypoint"sv, "AnyLdByValEntrypoint"sv, "AnyStByValEntrypoint"sv, + "AnyIsInstanceEntrypoint"sv, "AnyCall0Entrypoint"sv, "AnyCallShortEntrypoint"sv, + "AnyCallRangeEntrypoint"sv, "AnyCallThis0Entrypoint"sv, "AnyCallThisShortEntrypoint"sv, + "AnyCallThisRangeEntrypoint"sv, "AnyCallNew0Entrypoint"sv, "AnyCallNewShortEntrypoint"sv, + "AnyCallNewRangeEntrypoint"sv, #ifdef PANDA_WITH_ETS "LookupGetterByNameShortEntrypoint"sv, "LookupGetterByNameLongEntrypoint"sv, "LookupGetterByNameObjEntrypoint"sv, "LookupSetterByNameShortEntrypoint"sv, "LookupSetterByNameLongEntrypoint"sv, "LookupSetterByNameObjEntrypoint"sv, diff --git a/static_core/plugins/ets/runtime/ets_platform_types.cpp b/static_core/plugins/ets/runtime/ets_platform_types.cpp index f488200132cdbd0f2051ebdb49f3745496bb02f8..d803ca1f59c03c4aa1a17a2c6021fbd57671cbc7 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.cpp +++ b/static_core/plugins/ets/runtime/ets_platform_types.cpp @@ -182,6 +182,10 @@ EtsPlatformTypes::EtsPlatformTypes([[maybe_unused]] EtsCoroutine *coro) findType(&EtsPlatformTypes::interopJSValue, JS_VALUE); + EtsPlatformTypes::interopJSValue->GetRuntimeClass()->SetXRefClass(); + EtsPlatformTypes::interopJSValue->SetValueTyped(); // JSValue should be ValueTyped + + findType(&EtsPlatformTypes::coreField, FIELD); findType(&EtsPlatformTypes::coreMethod, METHOD); findType(&EtsPlatformTypes::coreParameter, PARAMETER); diff --git a/static_core/plugins/ets/runtime/ets_stubs-inl.h b/static_core/plugins/ets/runtime/ets_stubs-inl.h index 621d3326dd6006fa546f0da911b17e1d45462cc9..acfa75fc216d0154201c04f13f2b74245e341f3d 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" @@ -419,6 +420,66 @@ ALWAYS_INLINE inline Method *GetMethodByName(EtsCoroutine *coro, ETSStubCacheInf return callee; } +ALWAYS_INLINE inline ObjectHeader *PluginAnyCallThis(ManagedThread *thread, ObjectHeader *thisObj, + panda_file::File::StringData name, Spanargs) +{ + return EtsCallThis(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(thisObj), name, args)->GetCoreType(); +} + +ALWAYS_INLINE inline ObjectHeader *PluginAnyCall(ManagedThread *thread, ObjectHeader *funcObj, + Span args) +{ + return EtsCall(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(funcObj), args)->GetCoreType(); +} + +ALWAYS_INLINE inline ObjectHeader *PluginAnyNewRange(ManagedThread *thread, ObjectHeader *ctor, + Span args) +{ + return EtsNewRange(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(ctor), args)->GetCoreType(); +} + +ALWAYS_INLINE inline bool PluginAnyIsinstance(ManagedThread *thread, ObjectHeader *lhsObj, ObjectHeader *rhsObj) +{ + return EtsAnyIsinstance(EtsCoroutine::CastFromThread(thread), EtsObject::FromCoreType(lhsObj), + EtsObject::FromCoreType(rhsObj)); +} + +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 70ea899b4c4a325372bbc496d2772e8cb43fad4c..497295d47223057c34a1e8bda63e1e20f873272b 100644 --- a/static_core/plugins/ets/runtime/ets_stubs.cpp +++ b/static_core/plugins/ets/runtime/ets_stubs.cpp @@ -19,8 +19,15 @@ #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; +#endif template static std::optional GetBoxedNumericValue(EtsPlatformTypes const *ptypes, EtsObject *obj) @@ -96,6 +103,17 @@ bool EtsValueTypedEquals(EtsCoroutine *coro, EtsObject *obj1, EtsObject *obj2) auto cls2 = obj2->GetClass(); ASSERT(cls1->IsValueTyped() && cls2->IsValueTyped()); + if (cls1->GetRuntimeClass()->IsXRefClass() && cls2->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + auto jsObj1 = interop::js::JSValue::FromEtsObject(obj1); + auto jsObj2 = interop::js::JSValue::FromEtsObject(obj2); + return interop::js::JSRuntimeStrictEqual(jsObj1, jsObj2) != 0; +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } + auto ptypes = PlatformTypes(coro); ASSERT(ptypes != nullptr); @@ -174,6 +192,15 @@ EtsString *EtsGetTypeof(EtsCoroutine *coro, EtsObject *obj) return EtsString::CreateFromMUtf8("object"); } + if (cls->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + return EtsString::CreateFromMUtf8("object"); // issue: should always be reference and return object +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } + if (cls->IsFunctionReference()) { return EtsString::CreateFromMUtf8("function"); } @@ -217,6 +244,15 @@ bool EtsGetIstrue(EtsCoroutine *coro, EtsObject *obj) if (!cls->IsValueTyped()) { return true; } + if (cls->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + auto jsObj = interop::js::JSValue::FromEtsObject(obj); + return interop::js::JSRuntimeStrictEqual(jsObj, ets::interop::js::JSRuntimeNewJSValueBoolean(1)) != 0; +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } if (cls->IsFunctionReference()) { return true; } @@ -250,4 +286,267 @@ 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 { + // ASSERTION. LHS is not a JSValue + // then it is must a static object + if (valObj->IsStringClass()) { + auto fieldName = EtsString::FromEtsObject(valObj)->GetDataMUtf8(); + auto fieldIndex = thisObj->GetClass()->GetFieldIndexByName(utf::Mutf8AsCString(fieldName)); + EtsField *field = thisObj->GetClass()->GetFieldByIndex(fieldIndex); + if (field == nullptr) { + return nullptr; + } + + return GetPropertyValue(coro, thisObj, field); + } + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), valObj); + if (unboxedValue.has_value()) { + auto getMethod = thisObj->GetClass()->GetInstanceMethod(ark::ets::GET_INDEX_METHOD, nullptr); + + std::array args {ark::Value(reinterpret_cast(thisObj)), ark::Value(unboxedValue.value())}; + ark::Value res = getMethod->GetPandaMethod()->Invoke(coro, args.data()); + return EtsObject::FromCoreType(res.GetAs()); + } + + LOG(ERROR, RUNTIME) << "Invalid abc: can not be here"; + return nullptr; + } +} + +bool EtsAnyIsinstance([[maybe_unused]] EtsCoroutine *coro, EtsObject *lhsObj, EtsObject *rhsObj) +{ + if (lhsObj->GetClass()->GetRuntimeClass()->IsXRefClass() && rhsObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + // ASSEERTION. instanceof will be compiled to this instruction + // if and only if LHS is JSValue + ASSERT(interop::js::JSRuntimeIsJSValue(rhsObj)); + + // 1. if LHS is not a JSValue + // then it is not an instance of JSValue + if (!interop::js::JSRuntimeIsJSValue(lhsObj)) { + return false; + } + + // 2. check if LHS is an instance of RHS + return interop::js::JSRuntimeInstanceOfDynamic(JSValue::FromEtsObject(lhsObj), JSValue::FromEtsObject(rhsObj)); +#else + LOG(FATAL, RUNTIME) << "Met dynamic object without interop build"; + UNREACHABLE(); +#endif + } + return false; +} + +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 { + // ASSERTION. LHS is not a JSValue + // then it is must a static object + auto getMethod = thisObj->GetClass()->GetInstanceMethod(ark::ets::GET_INDEX_METHOD, nullptr); + + std::array args {ark::Value(reinterpret_cast(thisObj)), ark::Value(index)}; + ark::Value res = getMethod->GetPandaMethod()->Invoke(coro, args.data()); + return EtsObject::FromCoreType(res.GetAs()); + + LOG(ERROR, RUNTIME) << "Invalid abc: can not be here"; + 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; + } +} + +bool 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); + return true; + } else if (key->GetClass()->GetRuntimeClass()->IsXRefClass()) { + interop::js::SetPropertyWithObject(thisValue, JSValue::FromEtsObject(key), value); + return true; + } + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), key); // zzm: buggy here + if (unboxedValue.has_value()) { + interop::js::SetIndexedPropertyWithObject(thisValue, unboxedValue.value(), value); + return true; + } +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + // ASSERTION. LHS is not a JSValue + // then it is must a static object + if (key->IsStringClass()) { + auto fieldName = EtsString::FromEtsObject(key)->GetDataMUtf8(); + auto fieldIndex = obj->GetClass()->GetFieldIndexByName(utf::Mutf8AsCString(fieldName)); + EtsField *field = obj->GetClass()->GetFieldByIndex(fieldIndex); + if (field == nullptr) { + return false; + } + + return SetPropertyValue(coro, obj, field, value); + } + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), value); + if (unboxedValue.has_value()) { + auto getMethod = obj->GetClass()->GetInstanceMethod(ark::ets::SET_INDEX_METHOD, nullptr); + + std::array args {ark::Value(reinterpret_cast(obj)), ark::Value(unboxedValue.value()), + ark::Value(reinterpret_cast(value))}; + getMethod->GetPandaMethod()->Invoke(coro, args.data()); + + return true; + } + + LOG(ERROR, RUNTIME) << "Invalid abc: can not be here"; + return false; + } + UNREACHABLE(); +} + +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; + } +} + +bool 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); + return true; +#else + LOG(FATAL, RUNTIME) << "Find Dynamic Object without interop build"; + UNREACHABLE(); +#endif + } else { + // ASSERTION. LHS is not a JSValue + // then it is must a static object + auto unboxedValue = GetBoxedNumericValue(PlatformTypes(coro), value); + if (unboxedValue.has_value()) { + auto getMethod = obj->GetClass()->GetInstanceMethod(ark::ets::SET_INDEX_METHOD, nullptr); + + std::array args {ark::Value(reinterpret_cast(obj)), ark::Value(idx), + ark::Value(reinterpret_cast(value))}; + getMethod->GetPandaMethod()->Invoke(coro, args.data()); + + return true; + } + } + UNREACHABLE(); +} + +EtsObject *EtsCallThis([[maybe_unused]] EtsCoroutine *coro, EtsObject *thisObj, + [[maybe_unused]] panda_file::File::StringData name, [[maybe_unused]] Span args) +{ + if (thisObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + auto thisValue = JSValue::FromEtsObject(thisObj); + EtsObject *function = interop::js::GetPropertyObjectByString(thisValue, utf::Mutf8AsCString(name.data)); + if (!function->GetClass()->GetRuntimeClass()->IsXRefClass()) { + return nullptr; + } + return interop::js::InvokeWithObjectReturn(thisValue, JSValue::FromEtsObject(function), args); +#else + LOG(FATAL, RUNTIME) << "Met dynamic object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} + +EtsObject *EtsCall([[maybe_unused]] EtsCoroutine *coro, EtsObject *funcObj, [[maybe_unused]] Span args) +{ + if (funcObj->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + auto function = interop::js::JSValue::FromEtsObject(funcObj); // get jsvalue from 1.1 object + return interop::js::InvokeWithObjectReturn(function, args); +#else + LOG(FATAL, RUNTIME) << "Met dynamic object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} + +EtsObject *EtsNewRange([[maybe_unused]] EtsCoroutine *coro, EtsObject *ctor, [[maybe_unused]] Span args) +{ + if (ctor->GetClass()->GetRuntimeClass()->IsXRefClass()) { +#ifdef PANDA_ETS_INTEROP_JS + auto initFunction = interop::js::JSValue::FromEtsObject(ctor); // v1 + return interop::js::CreateObject(initFunction, args); +#else + LOG(FATAL, RUNTIME) << "Met dynamic object without interop build"; + UNREACHABLE(); +#endif + } else { + return nullptr; + } +} } // 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..27a3ff7a9078eb8c2c27b989beeaeed3bc171d87 100644 --- a/static_core/plugins/ets/runtime/ets_stubs.h +++ b/static_core/plugins/ets/runtime/ets_stubs.h @@ -47,6 +47,25 @@ EtsString *EtsGetTypeof(EtsCoroutine *coro, EtsObject *obj); bool EtsGetIstrue(EtsCoroutine *coro, EtsObject *obj); +EtsObject *EtsCallThis([[maybe_unused]] EtsCoroutine *coro, EtsObject *thisObj, + [[maybe_unused]] panda_file::File::StringData name, [[maybe_unused]] Span args); +EtsObject *EtsCall([[maybe_unused]] EtsCoroutine *coro, EtsObject *funcObj, [[maybe_unused]] Span args); +EtsObject *EtsNewRange([[maybe_unused]] EtsCoroutine *coro, EtsObject *ctor, + [[maybe_unused]] Span args); +bool EtsAnyIsinstance(EtsCoroutine *coro, EtsObject *lhsObj, EtsObject *rhsObj); + +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); + +bool EtsStByVal(EtsCoroutine *coro, EtsObject *obj, EtsObject *valObj, EtsObject *value); + +void EtsStByName(EtsCoroutine *coro, EtsObject *obj, panda_file::File::StringData propName, EtsObject *value); + +bool 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/ets_utils.cpp b/static_core/plugins/ets/runtime/ets_utils.cpp index fcf69e25bcbcfbd7e5af9f3c13ca01d825693f93..3f0810e758d0fdd12a447f0d18efa13eba8c7b65 100644 --- a/static_core/plugins/ets/runtime/ets_utils.cpp +++ b/static_core/plugins/ets/runtime/ets_utils.cpp @@ -139,4 +139,87 @@ EtsField *ManglingUtils::GetFieldIDByDisplayName(EtsClass *klass, const PandaStr return field; } + +EtsObject *GetPropertyValue(EtsCoroutine *coro, const EtsObject *etsObj, EtsField *field) +{ + EtsType type = field->GetEtsType(); + switch (type) { + case EtsType::BOOLEAN: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::BYTE: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::CHAR: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::SHORT: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::INT: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::LONG: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::FLOAT: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::DOUBLE: { + auto etsVal = etsObj->GetFieldPrimitive(field); + return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); + } + case EtsType::OBJECT: { + return reinterpret_cast(etsObj->GetFieldObject(field)); + } + default: + return nullptr; + } +} + +bool SetPropertyValue(EtsCoroutine *coro, EtsObject *etsObj, EtsField *field, EtsObject *valToSet) +{ + ark::Value etsVal = GetUnboxedValue(coro, valToSet); + EtsType type = field->GetEtsType(); + switch (type) { + case EtsType::BOOLEAN: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::BYTE: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::CHAR: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::SHORT: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::INT: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::LONG: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::FLOAT: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::DOUBLE: + etsObj->SetFieldPrimitive(field, etsVal.GetAs()); + break; + case EtsType::OBJECT: + etsObj->SetFieldObject(field, reinterpret_cast(valToSet)); + break; + default: + return false; + } + + return true; +} } // namespace ark::ets diff --git a/static_core/plugins/ets/runtime/ets_utils.h b/static_core/plugins/ets/runtime/ets_utils.h index 755519fa16c3fa80760e523fed50ec589e1c0af0..a639f57c0066af47e3764a841cf9d42ccb5a924f 100644 --- a/static_core/plugins/ets/runtime/ets_utils.h +++ b/static_core/plugins/ets/runtime/ets_utils.h @@ -32,6 +32,9 @@ EtsObject *GetBoxedValue(EtsCoroutine *coro, Value value, EtsType type); Value GetUnboxedValue(EtsCoroutine *coro, EtsObject *obj); +EtsObject *GetPropertyValue(EtsCoroutine *coro, const EtsObject *etsObj, EtsField *field); +bool SetPropertyValue(EtsCoroutine *coro, EtsObject *etsObj, EtsField *field, EtsObject *valToSet); + class LambdaUtils { public: PANDA_PUBLIC_API static void InvokeVoid(EtsCoroutine *coro, EtsObject *lambda); 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..6eb5c7d533f4c475d9f3b4355edc8273638b6e2f 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 @@ -405,8 +405,8 @@ uint8_t JSRuntimeInstanceOfStatic(JSValue *etsJsValue, EtsClass *etsCls) std::pair ResolveModuleName(std::string_view module) { static const std::unordered_set NATIVE_MODULE_LIST = { - "@system.app", "@ohos.app", "@system.router", "@system.curves", - "@ohos.curves", "@system.matrix4", "@ohos.matrix4"}; + "@system.app", "@ohos.app", "@system.router", "@system.curves", + "@ohos.curves", "@system.matrix4", "@ohos.matrix4"}; constexpr std::string_view REQUIRE = "require"; constexpr std::string_view REQUIRE_NAPI = "requireNapi"; @@ -498,7 +498,7 @@ uint8_t JSRuntimeStrictEqual([[maybe_unused]] JSValue *lhs, [[maybe_unused]] JSV bool result = false; NAPI_CHECK_FATAL(napi_strict_equals(env, JSConvertJSValue::WrapWithNullCheck(env, lhs), - JSConvertJSValue::WrapWithNullCheck(env, rhs), &result)); + JSConvertJSValue::WrapWithNullCheck(env, rhs), &result)); return static_cast(result); } @@ -512,10 +512,23 @@ uint8_t JSRuntimeHasProperty(JSValue *object, EtsString *name) bool result = false; NAPI_CHECK_FATAL(napi_has_property(env, JSConvertJSValue::WrapWithNullCheck(env, object), - JSConvertString::WrapWithNullCheck(env, name), &result)); + JSConvertString::WrapWithNullCheck(env, name), &result)); 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,173 @@ 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 *GetPropertyObjectByString(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 *funcObj, 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 refconv = JSRefConvertResolve(ctx, arg->GetClass()->GetRuntimeClass()); + auto realArg = refconv->Wrap(ctx, arg); + realArgs.push_back(realArg); + } + + napi_value retVal; + napi_status jsStatus; + auto recvEtsObject = JSConvertJSValue::WrapWithNullCheck(env, nullptr); + auto funcEtsObject = JSConvertJSValue::WrapWithNullCheck(env, funcObj); + { + 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(); +} + +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 refconv = JSRefConvertResolve(ctx, arg->GetClass()->GetRuntimeClass()); + auto realArg = refconv->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) @@ -698,6 +869,38 @@ JSValue *JSRuntimeInstantiate(JSValue *callable, EtsArray *args) return JSConvertJSValue::UnwrapWithNullCheck(ctx, env, retVal).value(); } +EtsObject *CreateObject(JSValue *ctor, 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 refconv = JSRefConvertResolve(ctx, arg->GetClass()->GetRuntimeClass()); + auto realArg = refconv->Wrap(ctx, arg); + realArgs.push_back(realArg); + } + + auto initFunc = JSConvertJSValue::WrapWithNullCheck(env, ctor); + napi_status jsStatus; + napi_value retVal; + { + ScopedNativeCodeThread nativeScope(coro); + jsStatus = napi_new_instance(env, initFunc, realArgs.size(), realArgs.data(), &retVal); + } + + if (jsStatus != napi_ok) { + ctx->ForwardJSException(coro); + return nullptr; + } + return JSConvertEtsObject::UnwrapWithNullCheck(ctx, env, retVal).value(); +} + uint8_t JSRuntimeIsPromise(JSValue *object) { auto coro = EtsCoroutine::GetCurrent(); 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..f01819e8df4cc68e68c6a449107582ca587d8e36 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,17 @@ 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 *GetPropertyObjectByString(JSValue *object, const char *property); +EtsObject *GetNamedPropertyObject(JSValue *object, const char *property); +JSValue *GetNamedPropertyJSValue(JSValue *object, const char *property); +EtsObject *InvokeWithObjectReturn(JSValue *thisObj, JSValue *function, Span args); +EtsObject *InvokeWithObjectReturn(JSValue *funcObj, Span args); +EtsObject *CreateObject(JSValue *ctor, Span args); +bool JSValueIsTrue(JSValue *value); void *CompilerGetJSNamedProperty(void *val, char *propStr); void *CompilerGetJSProperty(void *val, void *prop); void *CompilerGetJSElement(void *val, int32_t index); @@ -127,7 +138,7 @@ void JSValueNamedSetter(JSValue *etsJsValue, EtsString *etsPropName, typename T: } template -typename T::cpptype JSValueIndexedGetter(JSValue *etsJsValue, int32_t index) +typename T::cpptype JSValueIndexedGetter(JSValue *etsJsValue, long index) { auto coro = EtsCoroutine::GetCurrent(); auto ctx = InteropCtx::Current(coro); @@ -166,7 +177,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..457463a725fdbcecdd16fd10ffc3e677ef09277c 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,8 +401,8 @@ JSCONVERT_UNWRAP(EtsNull) #undef JSCONVERT_UNWRAP template -static ALWAYS_INLINE inline std::optional JSValueGetByName(InteropCtx *ctx, JSValue *jsvalue, - const char *name) +ALWAYS_INLINE inline std::optional JSValueGetByName(InteropCtx *ctx, JSValue *jsvalue, + const char *name) { auto env = ctx->GetJSEnv(); napi_value jsVal = jsvalue->GetNapiValue(env); @@ -405,8 +418,8 @@ static ALWAYS_INLINE inline std::optional JSValueGetByName( } template -[[nodiscard]] static ALWAYS_INLINE inline bool JSValueSetByName(InteropCtx *ctx, JSValue *jsvalue, const char *name, - typename T::cpptype etsPropVal) +[[nodiscard]] ALWAYS_INLINE inline bool JSValueSetByName(InteropCtx *ctx, JSValue *jsvalue, const char *name, + typename T::cpptype etsPropVal) { auto env = ctx->GetJSEnv(); napi_value jsVal = jsvalue->GetNapiValue(env); diff --git a/static_core/plugins/ets/runtime/static_object_accessor.cpp b/static_core/plugins/ets/runtime/static_object_accessor.cpp index 0569ba5398828baf8ee58b1d59974ad38beff4b7..54cf528fb492319c26649cc85748e36312a7e969 100644 --- a/static_core/plugins/ets/runtime/static_object_accessor.cpp +++ b/static_core/plugins/ets/runtime/static_object_accessor.cpp @@ -34,50 +34,6 @@ bool StaticObjectAccessor::HasProperty([[maybe_unused]] panda::ThreadHolder *thr return etsObj->GetClass()->GetFieldIDByName(name) != nullptr; } -panda::BoxedValue GetPropertyValue(EtsCoroutine *coro, const EtsObject *etsObj, EtsField *field) -{ - EtsType type = field->GetEtsType(); - switch (type) { - case EtsType::BOOLEAN: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::BYTE: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::CHAR: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::SHORT: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::INT: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::LONG: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::FLOAT: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::DOUBLE: { - auto etsVal = etsObj->GetFieldPrimitive(field); - return reinterpret_cast(GetBoxedValue(coro, ark::Value(etsVal), field->GetEtsType())); - } - case EtsType::OBJECT: { - return reinterpret_cast(etsObj->GetFieldObject(field)); - } - default: - return nullptr; - } -} - panda::BoxedValue StaticObjectAccessor::GetProperty([[maybe_unused]] panda::ThreadHolder *thread, const panda::BaseObject *obj, const char *name) { @@ -92,7 +48,7 @@ panda::BoxedValue StaticObjectAccessor::GetProperty([[maybe_unused]] panda::Thre if (field == nullptr) { return nullptr; } - return GetPropertyValue(coro, etsObj, field); + return reinterpret_cast(GetPropertyValue(coro, etsObj, field)); } bool StaticObjectAccessor::SetProperty([[maybe_unused]] panda::ThreadHolder *thread, panda::BaseObject *obj, @@ -104,45 +60,14 @@ bool StaticObjectAccessor::SetProperty([[maybe_unused]] panda::ThreadHolder *thr if (etsObj == nullptr) { return false; } - ark::Value etsVal = GetUnboxedValue(coro, reinterpret_cast(value)); + auto fieldIndex = etsObj->GetClass()->GetFieldIndexByName(name); EtsField *field = etsObj->GetClass()->GetFieldByIndex(fieldIndex); if (field == nullptr) { return false; } - EtsType type = field->GetEtsType(); - switch (type) { - case EtsType::BOOLEAN: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::BYTE: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::CHAR: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::SHORT: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::INT: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::LONG: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::FLOAT: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::DOUBLE: - etsObj->SetFieldPrimitive(field, etsVal.GetAs()); - break; - case EtsType::OBJECT: - etsObj->SetFieldObject(field, reinterpret_cast(value)); - break; - default: - return false; - } - return true; + + return SetPropertyValue(coro, etsObj, field, reinterpret_cast(value)); } bool StaticObjectAccessor::HasElementByIdx([[maybe_unused]] panda::ThreadHolder *thread, 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/plugins/ets/tests/interop_js/cmake/interop_js_tests_arkjsvm.cmake b/static_core/plugins/ets/tests/interop_js/cmake/interop_js_tests_arkjsvm.cmake index 276025f4bb997a30ad5ec0a402efc85683ac4cce..4fae23fe68a524b0425dd5539d68e96ed54253bf 100644 --- a/static_core/plugins/ets/tests/interop_js/cmake/interop_js_tests_arkjsvm.cmake +++ b/static_core/plugins/ets/tests/interop_js/cmake/interop_js_tests_arkjsvm.cmake @@ -91,7 +91,7 @@ endfunction(compile_dynamic_file) # ETS_CONFIG # path/to/arktsconfig.json # PACKAGE_NAME -# unit1_test +# unit1_test # ) function(panda_ets_interop_js_gtest TARGET) # Parse arguments @@ -99,7 +99,7 @@ function(panda_ets_interop_js_gtest TARGET) ARG "COMPILATION_JS_WITH_CJS_ON;COMPILATION_WITH_RUNTIMELINKER" "ETS_CONFIG;PACKAGE_NAME" - "CPP_SOURCES;ETS_SOURCES;JS_SOURCES;TS_SOURCES;JS_TEST_SOURCE;LIBRARIES" + "CPP_SOURCES;ETS_SOURCES;JS_SOURCES;TS_SOURCES;JS_TEST_SOURCE;ASM_SOURCE;LIBRARIES" ${ARGN} ) @@ -112,12 +112,14 @@ function(panda_ets_interop_js_gtest TARGET) OUTPUT_SUFFIX ".so" ) - set(TARGET_GTEST_PACKAGE ${TARGET}_gtest_package) - panda_ets_package_gtest(${TARGET_GTEST_PACKAGE} - ETS_SOURCES ${ARG_ETS_SOURCES} - ETS_CONFIG ${ARG_ETS_CONFIG} - ) - add_dependencies(${TARGET} ${TARGET_GTEST_PACKAGE}) + if(DEFINED ARG_ETS_SOURCES) + set(TARGET_GTEST_PACKAGE ${TARGET}_gtest_package) + panda_ets_package_gtest(${TARGET_GTEST_PACKAGE} + ETS_SOURCES ${ARG_ETS_SOURCES} + ETS_CONFIG ${ARG_ETS_CONFIG} + ) + add_dependencies(${TARGET} ${TARGET_GTEST_PACKAGE}) + endif() set(JS_COMPILATION_OPTIONS --module --merge-abc --enable-ets-implements) if(ARG_COMPILATION_JS_WITH_CJS_ON) @@ -141,21 +143,32 @@ function(panda_ets_interop_js_gtest TARGET) ) endif() - # if not set PACKAGE_NAME, using first ets file as its name; - set(ETS_SOURCES_NUM) - list(LENGTH ARG_ETS_SOURCES ETS_SOURCES_NUM) - if(NOT DEFINED ARG_PACKAGE_NAME AND ${ETS_SOURCES_NUM} EQUAL 1) - list(GET ARG_ETS_SOURCES 0 PACKATE_FILE) - get_filename_component(ARG_PACKAGE_NAME ${PACKATE_FILE} NAME_WE) - elseif(NOT DEFINED ARG_PACKAGE_NAME) - message(FATAL_ERROR "Please provide PACKAGE_NAME for ${TARGET}") + if(DEFINED ARG_ASM_SOURCE) + get_filename_component(ASM_DIR_PATH ${ARG_ASM_SOURCE} DIRECTORY) + get_filename_component(ASM_FILE_NAME ${ARG_ASM_SOURCE} NAME) + add_panda_assembly(TARGET ${TARGET}_asm_abc INDIR ${ASM_DIR_PATH} SOURCE ${ASM_FILE_NAME} + OUTDIR ${CMAKE_CURRENT_BINARY_DIR} TARGETNAME ${TARGET}_asm) + set(ARK_ETS_INTEROP_JS_GTEST_ASM_ABC_PATH "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_asm.abc") endif() - # Add launcher <${TARGET}_gtests> target - set(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH_PATH ${PANDA_BINARY_ROOT}/abc-gtests/${TARGET_GTEST_PACKAGE}.zip) - if(ARG_COMPILATION_WITH_RUNTIMELINKER) - set(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH_PATH "") + # if not set PACKAGE_NAME, using first ets file as its name; + if(DEFINED ARG_ETS_SOURCES) + set(ETS_SOURCES_NUM) + list(LENGTH ARG_ETS_SOURCES ETS_SOURCES_NUM) + if(NOT DEFINED ARG_PACKAGE_NAME AND ${ETS_SOURCES_NUM} EQUAL 1) + list(GET ARG_ETS_SOURCES 0 PACKATE_FILE) + get_filename_component(ARG_PACKAGE_NAME ${PACKATE_FILE} NAME_WE) + elseif(NOT DEFINED ARG_PACKAGE_NAME) + message(FATAL_ERROR "Please provide PACKAGE_NAME for ${TARGET}") + endif() + + # Add launcher <${TARGET}_gtests> target + set(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH_PATH ${PANDA_BINARY_ROOT}/abc-gtests/${TARGET_GTEST_PACKAGE}.zip) + if(ARG_COMPILATION_WITH_RUNTIMELINKER) + set(ARK_ETS_INTEROP_JS_GTEST_ABC_PATH_PATH "") + endif() endif() + panda_ets_add_gtest( NAME ${TARGET} NO_EXECUTABLE @@ -166,6 +179,7 @@ function(panda_ets_interop_js_gtest TARGET) "INTEROP_TEST_BUILD_DIR=${PANDA_BINARY_ROOT}/tests/ets_interop_js" "ARK_ETS_STDLIB_PATH=${PANDA_BINARY_ROOT}/plugins/ets/etsstdlib.abc" "ARK_ETS_INTEROP_JS_GTEST_ABC_PATH=${ARK_ETS_INTEROP_JS_GTEST_ABC_PATH_PATH}" + "ARK_ETS_INTEROP_JS_GTEST_ASM_ABC_PATH=${ARK_ETS_INTEROP_JS_GTEST_ASM_ABC_PATH}" "ARK_ETS_INTEROP_JS_GTEST_SOURCES=${CMAKE_CURRENT_SOURCE_DIR}" "ARK_ETS_INTEROP_JS_GTEST_DIR=${INTEROP_TESTS_DIR}" "FIXED_ISSUES=${FIXED_ISSUES}" @@ -187,6 +201,10 @@ function(panda_ets_interop_js_gtest TARGET) add_dependencies(${TARGET}_gtests ${TARGET}_dynamic_modules) endif() + if(DEFINED ARG_ASM_SOURCE) + add_dependencies(${TARGET}_gtests ${TARGET}_asm_abc) + endif() + add_dependencies(ets_interop_js_gtests ${TARGET}_gtests) endfunction(panda_ets_interop_js_gtest) @@ -288,4 +306,4 @@ function(panda_ets_interop_js_test TARGET) add_dependencies(${TARGET} ${TARGET}_js_modules) endif() add_dependencies(ets_interop_js_tests ${TARGET}) -endfunction(panda_ets_interop_js_test) +endfunction(panda_ets_interop_js_test) \ No newline at end of file diff --git a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp index b2d91b301c0c8e84b251a6f58f37243c3719d12f..b8b83993da8c5c65a5c899a4f991c240f89d3c74 100644 --- a/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp +++ b/static_core/plugins/ets/tests/interop_js/eacoro/attach_thread_test.cpp @@ -109,6 +109,7 @@ private: status = etsEnv->Class_FindStaticMethod(cls, name, nullptr, &method); ASSERT(status == ETS_OK); ani_int val; + std::cout << "method: " << name << std::endl; etsEnv->c_api->Class_CallStaticMethod_Int(etsEnv, cls, method, &val); ASSERT(val == 0); diff --git a/static_core/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js b/static_core/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js index 0b205282a269e0234b059792bf5bc86d8f5fb02a..388cd9ff3448860a7d2644d069ce332d60e38f22 100644 --- a/static_core/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js +++ b/static_core/plugins/ets/tests/interop_js/gtest_plugin/gtest_launcher.js @@ -64,8 +64,9 @@ function main() { let stdlibPath = helper.getEnvironmentVar('ARK_ETS_STDLIB_PATH'); let gtestAbcPath = helper.getEnvironmentVar('ARK_ETS_INTEROP_JS_GTEST_ABC_PATH'); + let asmAbcPath = helper.getEnvironmentVar('ARK_ETS_INTEROP_JS_GTEST_ASM_ABC_PATH'); + - let argv = helper.getArgv(); const arkJsNapiCliLastArgIdx = 5; @@ -75,13 +76,23 @@ function main() { return 1; } + let userPandaFiles = gtestAbcPath + if (asmAbcPath !== '') { + if (userPandaFiles === '') { + userPandaFiles += asmAbcPath + } else { + userPandaFiles += (':' + asmAbcPath); + } + } + let createRuntimeOptions = { 'log-level': 'info', 'log-components': 'ets_interop_js', - 'boot-panda-files': stdlibPath + ':' + gtestAbcPath, - 'panda-files': gtestAbcPath, + 'boot-panda-files': stdlibPath + ':' + userPandaFiles, + 'panda-files': userPandaFiles, 'gc-trigger-type': 'heap-trigger', 'compiler-enable-jit': 'false', + "interpreter-type": "cpp" }; if (gtestName === 'ets_interop_ts_to_ets_taskpool') { diff --git a/static_core/plugins/ets/tests/interop_js/tests/interop_isa/CMakeLists.txt b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..40b511e4e217aa4284dc0af2bebeb12cce05254d --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2024-2025 Huawei Device Co., Ltd. +# 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. + + +panda_ets_interop_js_gtest(ets_interop_js__interop_isa + CPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp + ASM_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/test.pa + JS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/index.js + ETS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test.ets + ETS_CONFIG ${ETS_CONFIG} +) diff --git a/static_core/plugins/ets/tests/interop_js/tests/interop_isa/index.js b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/index.js new file mode 100644 index 0000000000000000000000000000000000000000..439739c47d9613a7086c4f7bcf63a81410561555 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/index.js @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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. + */ +const etsVm = globalThis.gtest.etsVm; + +function testCallRange(a, b) { + return a + b; +} + +function testCall0() { + return 1; +} + +function testCallShort(a) { + return a + 1; +} + +class C { + f = 1; +} + +class TestNew0 { + field1 = 0; + constructor() { + } +} + +class TestNewRange { + field1; + field2; + + constructor(field1, field2) { + this.field1 = field1; + this.field2 = field2; + } + + baz() { + return 1; + } + + foo(a, b) { + return a + b; + } + + bar(a) { + return a + 1; + } +} + +class TestNewShort { + field1; + + constructor(field1) { + this.field1 = field1; + } +} + +let testInstanceOf = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "testIsInstance"); +let doTestCallRange = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCallRange"); +let doTestCall0 = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCall0"); +let doTestNew0 = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestNew0"); +let doTestNewRange = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestNewRange"); +let doTestCallThis0 = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCallThis0"); +let doTestCallThisRange = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCallThisRange"); +let doTestCallShort = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCallShort"); +let doTestCallThisShort = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestCallThisShort"); +let doTestNewShort = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestNewShort"); + +let doTestVal = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestVal"); +let doTestValName = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestValName"); +let doTestValNameV = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestValNameV"); +let doTestValIdx = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestValIdx"); +let doTestStVal = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestStVal"); +let doTestStValName = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestStValName"); +let doTestStValNameV = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestStValNameV"); +let doTestStValIdx = etsVm.getFunction("Ltest-static/ETSGLOBAL;", "doTestStValIdx"); + +function anyInstanceOfTest() { + ASSERT_TRUE(testInstanceOf(new C(), C)); + ASSERT_TRUE(!testInstanceOf({f: 1}, C)); +} + +function anyCallRangeTest() { + ASSERT_EQ(doTestCallRange(testCallRange, 0, 1), 1); +} + +function anyCall0Test() { + ASSERT_EQ(doTestCall0(testCall0), 1); +} + +function anyCallShortTest() { + ASSERT_EQ(doTestCallShort(testCallShort, 0), 1); +} + +function anyCallThisRangeTest() { + let obj = new TestNewRange(0, 1); + ASSERT_EQ(doTestCallThisRange(obj, 0, 1), 1); +} + +function anyCallThis0Test() { + let obj = new TestNewRange(0, 1); + ASSERT_EQ(doTestCallThis0(obj), 1); +} + +function anyCallThisShortTest() { + let obj = new TestNewRange(0, 1); + ASSERT_EQ(doTestCallThisShort(obj, 0), 1); +} + +function anyCallNewRangeTest() { + let obj = doTestNewRange(TestNewRange, 0, 1); + ASSERT_EQ(obj.field1, 0); + ASSERT_EQ(obj.field2, 1); +} + +function anyCallNew0Test() { + let obj = doTestNew0(TestNew0); + ASSERT_EQ(obj.field1, 0); +} + +function anyCallNewShortTest() { + let obj = doTestNewShort(TestNewShort, 1); + ASSERT_EQ(obj.field1, 1); +} + +function anyLdByValTest() { + ASSERT_EQ(doTestVal({a: 1}, "a"), 1); +} + +function anyLdByNameTest() { + ASSERT_EQ(doTestValName({a: 1}), 1); +} + +function anyLdByNameVTest() { + ASSERT_EQ(doTestValNameV({a: 1}), 1); +} + +function anyLdByIdxTest() { + ASSERT_EQ(doTestValIdx({1: 1}), 1); +} + +function anyStByValTest() { + let o = {a: 0}; + doTestStVal(o, "a", 1); + ASSERT_EQ(o.a, 1); +} + +function anyStByNameTest() { + let o = {a: 0}; + doTestStValName(o, 1); + ASSERT_EQ(o.a, 1); +} + +function anyStByNameVTest() { + let o = {a: 0}; + doTestStValNameV(o, 1); + ASSERT_EQ(o.a, 1); +} + +function anyStByIdxTest() { + let o = {1:0} + doTestStValIdx(o, 1); + ASSERT_EQ(o[1], 1); +} + +anyInstanceOfTest(); +anyCallRangeTest(); +anyCall0Test(); +anyCallShortTest(); +anyCallThisRangeTest(); +anyCallThis0Test(); +anyCallThisShortTest(); +anyCallNewRangeTest(); +anyCallNew0Test(); +anyCallNewShortTest(); +anyLdByValTest(); +anyLdByNameTest(); +anyLdByNameVTest(); +anyLdByIdxTest(); +anyStByValTest(); +anyStByNameTest(); +anyStByNameVTest(); +anyStByIdxTest(); diff --git a/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.cpp b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98ee352d30b199bafbde089f6a9339b1873f2e79 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.cpp @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * 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 +#include +#include "ets_interop_js_gtest.h" + +namespace ark::ets::interop::js::testing { + +class EtsInteropIsa : public EtsInteropTest { +}; + +TEST_F(EtsInteropIsa, test_interop_isa) +{ + ASSERT_TRUE(RunJsTestSuite("index.js")); +} + +} // namespace ark::ets::interop::js::testing diff --git a/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.ets b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.ets new file mode 100644 index 0000000000000000000000000000000000000000..cd10cf6b9c0cd2cc36d22e9c672ffd7bfadf0914 --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.ets @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2024-2025 Huawei Device Co., Ltd. + * 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. + */ diff --git a/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.pa b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.pa new file mode 100644 index 0000000000000000000000000000000000000000..76922d05e0c00431efca5386927aea43a239af4f --- /dev/null +++ b/static_core/plugins/ets/tests/interop_js/tests/interop_isa/test.pa @@ -0,0 +1,136 @@ +# source binary: ./build/test-static.abc + +.language eTS + +.record std.core.Object + +.record std.core.String + +.record std.interop.js.JSValue + +.record std.interop.js.JSRuntime + +.record test-static.ETSGLOBAL { +} + +.function u1 std.interop.js.JSRuntime.__initJSCallClass() + +.function std.interop.js.JSValue std.interop.js.JSRuntime.getPropertyJSValue(std.interop.js.JSValue a0, std.core.String a1) + +.function std.interop.js.JSValue std.interop.js.JSRuntime.getUndefined() + +.function u1 test-static.ETSGLOBAL.testIsInstance(std.core.Object a0, std.core.Object a1) { + lda.obj a0 + any.isinstance a1 + return +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCallRange(std.interop.js.JSValue a0, std.interop.js.JSValue a1, std.interop.js.JSValue a2) { + lda.obj a1 + sta.obj v1 + lda.obj a2 + sta.obj v2 + any.call.range a0, v1, 0x2 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCallShort(std.interop.js.JSValue a0, std.interop.js.JSValue a1) { + lda.obj a1 + sta.obj v1 + any.call.short a0, v1 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCallThisShort(std.interop.js.JSValue a0, std.interop.js.JSValue a1) { + lda.obj a1 + sta.obj v1 + any.call.this.short "bar", a0, v1 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCall0(std.interop.js.JSValue a0) { + any.call.0 a0 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestNew0(std.interop.js.JSValue a0) { + any.call.new.0 a0 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestNewRange(std.interop.js.JSValue a0, std.interop.js.JSValue a1, std.interop.js.JSValue a2) { + lda.obj a1 + sta.obj v1 + lda.obj a2 + sta.obj v2 + any.call.new.range a0, v1, 0x2 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestNewShort(std.interop.js.JSValue a0, std.interop.js.JSValue a1) { + lda.obj a1 + sta.obj v1 + any.call.new.short a0, v1 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCallThis0(std.interop.js.JSValue a0) { + any.call.this.0 "baz", a0 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestCallThisRange(std.interop.js.JSValue a0, std.interop.js.JSValue a1, std.interop.js.JSValue a2) { + lda.obj a1 + sta.obj v1 + lda.obj a2 + sta.obj v2 + any.call.this.range "foo", a0, v1, 0x2 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestVal(std.interop.js.JSValue a0, std.core.Object a1) { + any.ldbyval a0, a1 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestValName(std.interop.js.JSValue a0) { + any.ldbyname a0, "a" + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestValNameV(std.interop.js.JSValue a0) { + any.ldbyname.v v1, a0, "a" + lda.obj v1 + return.obj +} + +.function std.core.Object test-static.ETSGLOBAL.doTestValIdx(std.interop.js.JSValue a0) { + ldai 0x1 + any.ldbyidx a0 + return.obj +} + +.function void test-static.ETSGLOBAL.doTestStVal(std.interop.js.JSValue a0, std.core.Object a1, std.core.Object a2) { + lda.obj a2 + any.stbyval a0, a1 + return.void +} + +.function void test-static.ETSGLOBAL.doTestStValName(std.interop.js.JSValue a0, std.core.Object a1) { + lda.obj a1 + any.stbyname a0, "a" + return.void +} + +.function void test-static.ETSGLOBAL.doTestStValNameV(std.interop.js.JSValue a0, std.core.Object a1) { + any.stbyname.v a0, a1, "a" + return.void +} + +.function void test-static.ETSGLOBAL.doTestStValIdx(std.interop.js.JSValue a0, std.core.Object a1) { + ldai 0x1 + sta v0 + lda.obj a1 + any.stbyidx a0, v0 + return.void +} diff --git a/static_core/runtime/entrypoints/entrypoints.cpp b/static_core/runtime/entrypoints/entrypoints.cpp index 2287f0e5d826569b61897b695b5d81b00dc93134..0860bc3cce26aa56aa89ff4772c305a4c7bf7097 100644 --- a/static_core/runtime/entrypoints/entrypoints.cpp +++ b/static_core/runtime/entrypoints/entrypoints.cpp @@ -42,6 +42,11 @@ #include "intrinsics.h" #include "runtime/interpreter/vregister_iterator.h" +#ifdef PANDA_WITH_ETS +#include "plugins/ets/runtime/ets_stubs.h" +#include "plugins/ets/runtime/ets_stubs-inl.h" +#endif + namespace ark { using ark::compiler::TraceId; @@ -551,6 +556,248 @@ extern "C" Frame *CreateNativeFrameWithActualArgsAndSize(uint32_t size, uint32_t return new (Frame::FromExt(mem, extSz)) Frame(mem, method, prev, nregs, numActualArgs); } +// zzm +static void ThrowNPEIfNeeded(bool throwCond) +{ + if (UNLIKELY(throwCond)) { + interpreter::RuntimeInterface::ThrowNullPointerException(); + HandlePendingException(); + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyLdByValEntrypoint(ManagedThread *thread, ObjectHeader *thisObj, ObjectHeader *key) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + auto ldObj = ets::PluginAnyLdbyval(thread, thisObj, key); + ThrowNPEIfNeeded(ldObj == nullptr); + return ldObj; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyLdByIdxEntrypoint(ManagedThread *thread, ObjectHeader *thisObj, int32_t key) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + auto ldObj = ets::PluginAnyLdbyidx(thread, thisObj, key); + ThrowNPEIfNeeded(ldObj == nullptr); + return ldObj; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyLdByNameEntrypoint(ManagedThread *thread, Frame *frame, + ObjectHeader *thisObj, FileEntityId id) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + auto pf = frame->GetMethod()->GetPandaFile(); + auto ldObj = ets::PluginAnyLdbyname(thread, thisObj, pf->GetStringData(panda_file::File::EntityId(id))); + ThrowNPEIfNeeded(ldObj == nullptr); + return ldObj; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" void AnyStByValEntrypoint(ManagedThread *thread, ObjectHeader *thisObj, + ObjectHeader *key, ObjectHeader *val) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + ThrowNPEIfNeeded(key == nullptr); + ets::PluginAnyStbyval(thread, thisObj, key, val); + return; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" void AnyStByIdxEntrypoint(ManagedThread *thread, ObjectHeader *thisObj, + int32_t key, ObjectHeader *val) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + ets::PluginAnyStbyidx(thread, thisObj, key, val); + return; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" void AnyStByNameEntrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *thisObj, + FileEntityId id, ObjectHeader *val) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + auto pf = frame->GetMethod()->GetPandaFile(); + ets::PluginAnyStbyname(thread, thisObj, pf->GetStringData(panda_file::File::EntityId(id)), val); + return; + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" bool AnyIsInstanceEntrypoint(ManagedThread *thread, ObjectHeader *lhs, ObjectHeader *rhs) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(lhs == nullptr); + switch (lhs->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + ThrowNPEIfNeeded(rhs == nullptr); + return ets::PluginAnyIsinstance(thread, lhs, rhs); + } +#endif + default: + UNREACHABLE(); + } +} + +static inline ObjectHeader *AnyCall(ManagedThread *thread, ObjectHeader *func, Spanargs) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(func == nullptr); + switch (func->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + return ets::PluginAnyCall(thread, func, args); + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyCall0Entrypoint(ManagedThread *thread, ObjectHeader *func) +{ + return AnyCall(thread, func, Span()); +} + +extern "C" ObjectHeader *AnyCallShortEntrypoint(ManagedThread *thread, ObjectHeader *func, ObjectHeader *arg) +{ + std::array args = {arg}; + return AnyCall(thread, func, Span(args)); +} + +extern "C" ObjectHeader *AnyCallRangeEntrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *func, + uint8_t argStart, uint8_t argc) +{ + PandaVector args; + for (uint8_t i = 0; i < argc; i++) { + args.push_back(frame->GetVReg(argStart + i).template GetAs()); + } + return AnyCall(thread, func, Span(args)); +} + +static inline ObjectHeader *AnyCallThis(ManagedThread *thread, Frame *frame, ObjectHeader *thisObj, FileEntityId name, + Spanargs) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(thisObj == nullptr); + switch (thisObj->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + auto pf = frame->GetMethod()->GetPandaFile(); + return ets::PluginAnyCallThis(thread, thisObj, pf->GetStringData(panda_file::File::EntityId(name)), args); + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyCallThis0Entrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *thisObj, FileEntityId name) +{ + return AnyCallThis(thread, frame, thisObj, name, Span()); +} + +extern "C" ObjectHeader *AnyCallThisShortEntrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *thisObj, FileEntityId name, ObjectHeader *arg) +{ + std::array args = {arg}; + return AnyCallThis(thread, frame, thisObj, name, Span(args)); +} + +extern "C" ObjectHeader *AnyCallThisRangeEntrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *thisObj, FileEntityId name, + uint8_t argStart, uint8_t argc) +{ + PandaVector args; + for (uint8_t i = 0; i < argc; i++) { + args.push_back(frame->GetVReg(argStart + i).template GetAs()); + } + return AnyCallThis(thread, frame, thisObj, name, Span(args)); +} + +static inline ObjectHeader *AnyCallNew(ManagedThread *thread, ObjectHeader *ctor, Spanargs) +{ + std::cout << "zzm: irtoc entrypoint" << std::endl; + ThrowNPEIfNeeded(ctor == nullptr); + switch (ctor->template ClassAddr()->GetSourceLang()) { +#ifdef PANDA_WITH_ETS + case panda_file::SourceLang::ETS: { + return ets::PluginAnyNewRange(thread, ctor, args); + } +#endif + default: + UNREACHABLE(); + } +} + +extern "C" ObjectHeader *AnyCallNew0Entrypoint(ManagedThread *thread, ObjectHeader *ctor) +{ + return AnyCallNew(thread, ctor, Span()); +} + +extern "C" ObjectHeader *AnyCallNewShortEntrypoint(ManagedThread *thread, ObjectHeader *ctor, ObjectHeader *arg) +{ + std::array args = {arg}; + return AnyCallNew(thread, ctor, Span(args)); +} + +extern "C" ObjectHeader *AnyCallNewRangeEntrypoint(ManagedThread *thread, Frame *frame, ObjectHeader *ctor, + uint8_t argStart, uint8_t argc) +{ + PandaVector args; + for (uint8_t i = 0; i < argc; i++) { + args.push_back(frame->GetVReg(argStart + i).template GetAs()); + } + return AnyCallNew(thread, ctor, Span(args)); +} + template static Frame *CreateFrame(uint32_t nregs, Method *method, Frame *prev) { 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..cab2e65efbc2704e6f7f15fa5fbf14bdb6da76a8 100644 --- a/static_core/runtime/interpreter/interpreter-inl.h +++ b/static_core/runtime/interpreter/interpreter-inl.h @@ -59,6 +59,11 @@ #include "runtime/mem/vm_handle.h" #include "runtime/handle_base-inl.h" +#ifdef PANDA_WITH_ETS +#include "plugins/ets/runtime/ets_stubs.h" +#include "plugins/ets/runtime/ets_stubs-inl.h" +#endif + // ALWAYS_INLINE is mandatory attribute for handlers. There are cases which will be failed without it. namespace ark::interpreter { @@ -1207,64 +1212,227 @@ public: template ALWAYS_INLINE void HandleAnyCall0() { - LOG_INST() << "Unimplemented instruction call.0"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction call.0"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *funcObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (funcObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + PandaVector args; + auto ret = ark::ets::PluginAnyCall(this->GetThread(), funcObj, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallRange() { - LOG_INST() << "Unimplemented instruction any.call.range"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.range"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *funcObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (funcObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = this->GetInst().template GetImm(); + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto ret = ark::ets::PluginAnyCall(this->GetThread(), funcObj, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallShort() { - LOG_INST() << "Unimplemented instruction any.call.short"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.short"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *funcObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (funcObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = 1; // call short only have one param + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto ret = ark::ets::PluginAnyCall(this->GetThread(), funcObj, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallThis0() { - LOG_INST() << "Unimplemented instruction any.call.this.0"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.this.0"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *thisObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (thisObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto stringId = this->GetInst().template GetId(); + PandaVector args; + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + auto ret = ark::ets::PluginAnyCallThis(this->GetThread(), thisObj, pf->GetStringData(stringId.AsFileId()), + Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.this.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallThisRange() { - LOG_INST() << "Unimplemented instruction any.call.this.range"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.this.range"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *thisObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (thisObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = this->GetInst().template GetImm(); + auto stringId = this->GetInst().template GetId(); + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + auto ret = ark::ets::PluginAnyCallThis(this->GetThread(), thisObj, pf->GetStringData(stringId.AsFileId()), + Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.this.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallThisShort() { - LOG_INST() << "Unimplemented instruction any.call.this.short"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.this.short"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *thisObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (thisObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = 1; // call short only have one param + auto stringId = this->GetInst().template GetId(); + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); + auto ret = ark::ets::PluginAnyCallThis(this->GetThread(), thisObj, pf->GetStringData(stringId.AsFileId()), + Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.this.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallNew0() { - LOG_INST() << "Unimplemented instruction any.call.new.0"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.new.0"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *ctor = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (ctor->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + PandaVector args; + auto ret = ark::ets::PluginAnyNewRange(this->GetThread(), ctor, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallNewRange() { - LOG_INST() << "Unimplemented instruction any.call.new.range"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.new.range"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *ctor = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (ctor->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = this->GetInst().template GetImm(); + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto ret = ark::ets::PluginAnyNewRange(this->GetThread(), ctor, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } } template ALWAYS_INLINE void HandleAnyCallNewShort() { - LOG_INST() << "Unimplemented instruction any.call.new.short"; - UNREACHABLE(); + LOG_INST() << "Implemented instruction any.call.new.short"; + uint16_t vs1 = this->GetInst().template GetVReg(); + ObjectHeader *ctor = this->GetFrame()->GetVReg(vs1).template GetAs(); + // This should be generated from plugin.erb file + if (ctor->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + auto argc = 1; // call short only have one param + uint16_t arg_start = this->GetInst().template GetVReg(); + PandaVector args; + for (int i = 0; i < argc; i++) { + args.push_back(this->GetFrame()->GetVReg(arg_start + i).template GetAs()); + } + auto ret = ark::ets::PluginAnyNewRange(this->GetThread(), ctor, Span(args)); + this->GetAccAsVReg().SetReference(ret); + this->template MoveToNextInst(); + } else { + LOG_INST() << "Unimplemented instruction any.call.range for non-ets plugin"; + UNREACHABLE(); + } + } + + template + ALWAYS_INLINE void HandleAnyIsinstance() + { + LOG_INST() << "Implemented instruction any.isinstance"; + uint16_t vs1 = this->GetInst().template GetVReg(); + LOG_INST() << "any.isinstance v" << vs1; + + ObjectHeader *lhsObj = this->GetAcc().template GetAs(); + ObjectHeader *rhsObj = this->GetFrame()->GetVReg(vs1).template GetAs(); + + if (lhsObj->template ClassAddr()->GetSourceLang() == panda_file::SourceLang::ETS) { + if (ets::PluginAnyIsinstance(this->GetThread(), lhsObj, rhsObj)) { + this->GetAccAsVReg().SetPrimitive(1); + } else { + this->GetAccAsVReg().SetPrimitive(0); + } + + this->template MoveToNextInst(); + return; + } else { + LOG_INST() << "Unimplemented instruction any.isinstance for non-ets plugin"; + UNREACHABLE(); + } } template @@ -3855,8 +4023,21 @@ public: this->MoveToExceptionHandler(); } - // NOTE: handle it - UNREACHABLE(); + auto *pf = this->GetFrame()->GetMethod()->GetPandaFile(); +#ifdef PANDA_WITH_ETS + 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(); + } +#endif + this->template MoveToNextInst(); } template @@ -3874,8 +4055,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 +4079,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 @@ -3906,13 +4105,19 @@ 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 *val = this->GetFrame()->GetVReg(vs1).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 +4128,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 +4155,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 @@ -3960,13 +4183,18 @@ public: ObjectHeader *obj = this->GetFrame()->GetVReg(vs1).GetReference(); ObjectHeader *valObj = this->GetFrame()->GetVReg(vs2).GetReference(); - if (UNLIKELY(obj == nullptr || valObj == nullptr)) { - RuntimeIfaceT::ThrowNullPointerException(); - 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 +4207,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 +4234,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(); diff --git a/static_core/verification/absint/abs_int_inl.h b/static_core/verification/absint/abs_int_inl.h index 6a7a0637d253be488cca8f9f921613dcec10c8d8..6cd40643d4389d43b2c7183160f753e7ac1ac4da 100644 --- a/static_core/verification/absint/abs_int_inl.h +++ b/static_core/verification/absint/abs_int_inl.h @@ -3429,7 +3429,7 @@ public: bool HandleAnyCall0() { LOG_INST(); - return false; + return true; } template @@ -3663,6 +3663,16 @@ public: return true; } + template + bool HandleAnyIsinstance() + { + LOG_INST(); + DBGBRK(); + Sync(); + // NOTE: @MockMockBlack handle it + return true; + } + private: Type GetCachedType() const {