diff --git a/compiler/codegen_intrinsics_ecmascript.cpp b/compiler/codegen_intrinsics_ecmascript.cpp index d426b68db4c4f3f2e8b60cb525031566bf3f6cbc..7097c9e45b42c2a3e16add6d48611ca0d7806226 100644 --- a/compiler/codegen_intrinsics_ecmascript.cpp +++ b/compiler/codegen_intrinsics_ecmascript.cpp @@ -304,4 +304,20 @@ void Codegen::CreateDynObjectSetClass(IntrinsicInst *inst, [[maybe_unused]] Reg CreateStackMap(inst); } } + +void Codegen::CreateDynCallCheck([[maybe_unused]] IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src, + [[maybe_unused]] RegMask *lvrmask) +{ + auto exit_label = CreateSlowPath(inst, EntrypointId::DEOPTIMIZE)->GetLabel(); + + ScopedTmpReg tmp(GetEncoder()); + + LoadClassFromObject(tmp, src[0]); + GetEncoder()->EncodeLdr(tmp, false, + MemRef(tmp, -cross_values::GetJshclassHclassOffset(GetArch()) + + cross_values::GetJshclassBitfieldOffset(GetArch()))); + GetEncoder()->EncodeBitTestAndBranch(exit_label, tmp, + cross_values::GetJshclassBitfieldConstructorStartBit(GetArch()), true); +} + } // namespace panda::compiler diff --git a/compiler/ecmascript_extensions/ecmascript_codegen_extensions.cpp b/compiler/ecmascript_extensions/ecmascript_codegen_extensions.cpp index 868daf01de92fa54deed3491b7eb7324188f235f..ecd47d84a80a90271d81344e69e243b65a838b62 100644 --- a/compiler/ecmascript_extensions/ecmascript_codegen_extensions.cpp +++ b/compiler/ecmascript_extensions/ecmascript_codegen_extensions.cpp @@ -32,6 +32,7 @@ namespace panda::compiler { bool Codegen::GenerateEcmascriptEnvInPrologue() { if (GetRuntime()->IsEcmascriptRuntime()) { + SCOPED_DISASM_STR(this, "Ecmascript Environment in Method Prologue"); auto enc = GetEncoder(); auto cp_src_offset = GetGraph()->GetRuntime()->GetConstantPoolOffset(); @@ -66,7 +67,7 @@ bool Codegen::GenerateEcmascriptEnvInEpilogue() if (!GetRuntime()->IsEcmascriptRuntime()) { return false; } - + SCOPED_DISASM_STR(this, "Ecmascript Environment in Method Epilogue"); ScopedTmpReg js_env_reg(GetEncoder()); auto enc = GetEncoder(); diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/intrinsics_type_resolving_ecmascript.cpp index 836ccbdb4db303102f4266a507605c310eef8da0..c3e6633fd5562a9785901107db9f2ce9fc9999bb 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/intrinsics_type_resolving_ecmascript.cpp @@ -535,17 +535,18 @@ bool TypesResolving::InlineLdFalse(IntrinsicInst *intrinsics) bool TypesResolving::InlineLdHole(IntrinsicInst *intrinsics) { - return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_HOLE_TYPE, TaggedValue::VALUE_HOLE); + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_HOLE_TYPE, DataType::Any(TaggedValue::VALUE_HOLE)); } bool TypesResolving::InlineLdNull(IntrinsicInst *intrinsics) { - return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_NULL_TYPE, TaggedValue::VALUE_NULL); + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_NULL_TYPE, DataType::Any(TaggedValue::VALUE_NULL)); } bool TypesResolving::InlineLdUndefined(IntrinsicInst *intrinsics) { - return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE, TaggedValue::VALUE_UNDEFINED); + return InlineLdConstant(intrinsics, AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE, + DataType::Any(TaggedValue::VALUE_UNDEFINED)); } bool TypesResolving::InlineLdInfinity(IntrinsicInst *intrinsics) diff --git a/compiler/optimizer/code_generator/compiler_base_types.cpp b/compiler/optimizer/code_generator/compiler_base_types.cpp index 062282da93bc87074a75fefd600ca6c48ca0bd52..b79084ed8d42a6be5189b136f9a1a91c8d780acd 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.cpp +++ b/compiler/optimizer/code_generator/compiler_base_types.cpp @@ -122,9 +122,8 @@ static void CompareAnyTypeGenObject(Encoder *enc, const Reg &dst, const Reg &src } static void CompareAnyTypeGenObjectType(Codegen *codegen, Encoder *enc, const Reg &dst, const Reg &src, uint32_t type, - Condition fail_cc = Condition::NE) + LabelHolder::LabelId label, Condition fail_cc = Condition::NE) { - auto label = enc->CreateLabel(); enc->EncodeMov(dst, Imm(0)); CompareAnyTypeGenObject(enc, src, label); @@ -141,6 +140,13 @@ static void CompareAnyTypeGenObjectType(Codegen *codegen, Encoder *enc, const Re enc->EncodeJump(label, tmp_reg, Imm(type), fail_cc); enc->EncodeMov(dst, Imm(1U)); +} + +static void CompareAnyTypeGenObjectType(Codegen *codegen, Encoder *enc, const Reg &dst, const Reg &src, uint32_t type, + Condition fail_cc = Condition::NE) +{ + auto label = enc->CreateLabel(); + CompareAnyTypeGenObjectType(codegen, enc, dst, src, type, label, fail_cc); enc->BindLabel(label); } @@ -280,24 +286,12 @@ bool ecmascript::CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, Encod case AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: enc->EncodeOr(dst, src, Imm(panda::coretypes::TaggedValue::VALUE_FALSE)); return true; - case AnyBaseType::ECMASCRIPT_INT_TYPE: - if (dst.GetId() != src.GetId()) { - if (!cvai->GetInput(0).GetInst()->IsConst()) { - ASSERT(src_reg_type == DataType::INT32 || src_reg_type == DataType::UINT32); - } -#ifndef NDEBUG - enc->EncodeMov(dst, src); - constexpr uint32_t INT32_SIZE = 32U; - enc->EncodeShr(dst, dst, Imm(INT32_SIZE)); - auto ok_label = enc->CreateLabel(); - enc->EncodeJump(ok_label, dst, Imm(0), Condition::EQ); - enc->EncodeAbort(); - enc->BindLabel(ok_label); -#endif - enc->EncodeMov(dst, src); - } + case AnyBaseType::ECMASCRIPT_INT_TYPE: { + auto src_32 = enc_v->GetCodegen()->ConvertRegister(cvai->GetSrcReg(0), DataType::INT32); + enc->EncodeCast(dst, false, src_32, false); enc->EncodeOr(dst, dst, Imm(panda::coretypes::TaggedValue::TAG_INT)); return true; + } case AnyBaseType::ECMASCRIPT_DOUBLE_TYPE: enc->EncodeMov(dst, src); enc->EncodeAdd(dst, dst, Imm(panda::coretypes::TaggedValue::DOUBLE_ENCODE_OFFSET)); @@ -353,22 +347,24 @@ bool ecmascript::AnyTypeCheckGen(const AnyTypeCheckInst *check_inst, EncodeVisit CompareAnyTypeGenDouble(enc, tmp_reg, src, id); return true; case AnyBaseType::ECMASCRIPT_STRING_TYPE: - CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeString(codegen->GetArch())); + CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeString(codegen->GetArch()), + id); return true; case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: - CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeJsArray(codegen->GetArch())); + CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeJsArray(codegen->GetArch()), + id); return true; case AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, - cross_values::GetJstypeTransitionHandler(codegen->GetArch())); + cross_values::GetJstypeTransitionHandler(codegen->GetArch()), id); return true; case AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, - cross_values::GetJstypePrototypeHandler(codegen->GetArch())); + cross_values::GetJstypePrototypeHandler(codegen->GetArch()), id); return true; case AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE: CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, cross_values::GetJstypeJsArray(codegen->GetArch()), - Condition::LE); + id, Condition::LE); return true; case AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: { CompareAnyTypeGenBool(enc, tmp_reg, src, id); @@ -380,6 +376,10 @@ bool ecmascript::AnyTypeCheckGen(const AnyTypeCheckInst *check_inst, EncodeVisit case AnyBaseType::ECMASCRIPT_HOLE_TYPE: IsEqualToValGen(enc, tmp_reg, src, Imm(panda::coretypes::TaggedValue::VALUE_HOLE), id); return true; + case AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + CompareAnyTypeGenObjectType(codegen, enc, tmp_reg, src, + cross_values::GetJstypeJsFunction(codegen->GetArch()), id); + return true; default: return false; } diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp index a7f78f200fd38dc0604c1324b6d88ffc0c7ef46d..1ccd1c1b54a552d611d76479c21d6fd2a07f36c1 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp @@ -13,4 +13,85 @@ * limitations under the License. */ +#include "compiler_logger.h" +#include "optimizer/ir_builder/inst_builder.h" +#include "optimizer/ir_builder/ir_builder.h" +#include "optimizer/ir/inst.h" +#include "bytecode_instruction.h" +#include "bytecode_instruction-inl.h" +#include "include/coretypes/tagged_value.h" + +namespace panda::compiler { + +// NOLINTNEXTLINE(misc-definitions-in-headers) +void InstBuilder::BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_range, bool call_this, uint64_t num_args) +{ + constexpr size_t NUMBER_HIDE_ARGS = 3; + auto pc = GetPc(bc_inst->GetAddress()); + auto save_state = CreateSaveState(Opcode::SaveState, pc); + AddInstruction(save_state); + + auto input = GetDefinition(bc_inst->GetVReg(0)); + auto func_check = BuildAnyTypeCheckInst(pc, input, save_state, AnyBaseType::ECMASCRIPT_FUNCTION_TYPE); + + auto fn_class_check = GetGraph()->CreateInstIntrinsic(DataType::ANY, pc); + fn_class_check->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_DYN_CALL_CHECK); + AdjustFlags(fn_class_check->GetIntrinsicId(), fn_class_check); + fn_class_check->SetFlag(inst_flags::CAN_DEOPTIMIZE); + fn_class_check->ReserveInputs(1); + fn_class_check->AllocateInputTypes(GetGraph()->GetAllocator(), 1); + fn_class_check->AppendInput(func_check); + fn_class_check->AddInputType(DataType::ANY); + fn_class_check->AppendInput(save_state); + fn_class_check->AddInputType(DataType::NO_TYPE); + AddInstruction(fn_class_check); + + auto inst = GetGraph()->CreateInstCallDynamic(DataType::ANY, pc); + + inst->SetCanNativeException(true); + + size_t args_count = 0; + + // Take into account this argument for virtual call + if (is_range) { + args_count = bc_inst->GetImm64() + 1; + } else { + args_count = num_args; + } + + inst->ReserveInputs(args_count + 1); // '+1' for SaveState input + inst->AllocateInputTypes(GetGraph()->GetAllocator(), args_count + 1); + + inst->AppendInput(func_check); + inst->AddInputType(DataType::ANY); + + inst->AppendInput(FindOrCreateConstant(coretypes::TaggedValue::VALUE_UNDEFINED)); // newtarget argument + inst->AddInputType(DataType::ANY); + + if (!call_this) { + inst->AppendInput(FindOrCreateConstant(coretypes::TaggedValue::VALUE_UNDEFINED)); // this argument + inst->AddInputType(DataType::ANY); + } + + if (is_range) { + auto start_reg = bc_inst->GetVReg(0); + // start reg for Virtual call was added + for (size_t i = 0; i < args_count - 1; i++) { + inst->AppendInput(GetDefinition(start_reg + i + 1)); + inst->AddInputType(DataType::ANY); + } + } else { + for (size_t i = 0; i < args_count - NUMBER_HIDE_ARGS; i++) { + inst->AppendInput(GetDefinition(bc_inst->GetVReg(i + 1))); + inst->AddInputType(DataType::ANY); + } + } + inst->AppendInput(save_state); + inst->AddInputType(DataType::NO_TYPE); + AddInstruction(inst); + UpdateDefinitionAcc(inst); +} + +} // namespace panda::compiler + #include "ecmascript_inst_builder_gen.cpp" diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h index d4a6ed0ed6bd33a7e3c23439a51fb934c156ec05..20a5c069ce6fc001c8de39edf30c4af63c52ce7f 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.h +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.h @@ -21,4 +21,6 @@ template void BuildEcmaAsIntrinsics([[maybe_unused]] const BytecodeInstruction *bc_inst); void BuildEcmaFromIrtoc([[maybe_unused]] const BytecodeInstruction *bc_inst); +void BuildEcmaFnCall(const BytecodeInstruction *bc_inst, bool is_range, bool call_this, uint64_t num_args = 0); + #endif // PLUGINS_ECMASCRIPT_COMPILER_OPTIMIZER_IR_BUILDER_ECMASCRIPT_INST_BUILDER_H diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml index c928fd90639cf74508a3e4882a1d02c2b8c1a46e..1a93dab60cc5c5c0a2d14d4bc0a9d7606746ee90 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml +++ b/compiler/optimizer/ir_builder/ecmascript_inst_templates.yaml @@ -32,6 +32,42 @@ AddInstruction(cvat); AddInstruction(cmp_inst); AddInstruction(jmp_inst); + % when "CALL0DYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, false, 3); + } + % when "CALL1DYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, false, 4); + } + % when "CALL2DYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, false, 5); + } + % when "CALL3DYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, false, false, 6); + } + % when "CALLIRANGEDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, true, false); + } + % when "CALLITHISRANGEDYN" + if (graph_->IsBytecodeOptimizer()) { + BuildEcma(instruction); + } else { + BuildEcmaFnCall(instruction, true, true); + } % else BuildEcma(instruction); % end diff --git a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb index 3a70992e2b5c22b4005a057d891c9d5d817a0e13..cfc856db2fdb2264cab7032ed5264fa4854b1cc0 100644 --- a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb +++ b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb @@ -20,6 +20,7 @@ #include "bytecode_instruction.h" #include "bytecode_instruction-inl.h" #include "include/coretypes/tagged_value.h" + #include "irtoc_builder.cpp" namespace panda::compiler { diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index 191e9a7097f4d25b174ecfe581d0540789dfd082..063f289d454ef47d1ea878b5a35d5974ff7924c2 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -43,9 +43,9 @@ func_resolve_string_type: panda::compiler::ecmascript::GetAnyStringType func_is_any_type_can_be_subtype_of: panda::compiler::ecmascript::IsAnyTypeCanBeSubtypeOf list_types: - HOLE_TYPE: panda::compiler::DataType::Type::VOID - NULL_TYPE: panda::compiler::DataType::Type::VOID - UNDEFINED_TYPE: panda::compiler::DataType::Type::VOID + HOLE_TYPE: panda::compiler::DataType::Type::ANY + NULL_TYPE: panda::compiler::DataType::Type::ANY + UNDEFINED_TYPE: panda::compiler::DataType::Type::ANY INT_TYPE: panda::compiler::DataType::Type::INT32 DOUBLE_TYPE: panda::compiler::DataType::Type::FLOAT64 OBJECT_TYPE: panda::compiler::DataType::Type::REFERENCE @@ -56,6 +56,7 @@ PROTOTYPE_HANDLER_TYPE: panda::compiler::DataType::Type::REFERENCE SPECIAL_INDEXED_TYPE: panda::compiler::DataType::Type::REFERENCE BOOLEAN_TYPE: panda::compiler::DataType::Type::BOOL + FUNCTION_TYPE: panda::compiler::DataType::Type::REFERENCE Intrinsics: intrinsic_inline_inl: plugins/ecmascript/compiler/intrinsics_inline_ecmascript.inl intrinsic_type_resolving_inl_h: plugins/ecmascript/compiler/intrinsics_type_resolving_ecmascript.inl.h diff --git a/isa/isa.yaml b/isa/isa.yaml index 8c957bf1102780c8d0d7e2da778886b7d3d9a530..cd21082099ed38efa48efc661f730435357e152e 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -618,13 +618,13 @@ groups: acc: out:top prefix: ecma format: [pref_op_imm_16_v_8] - properties: [call, not_compilable] + properties: [call] intrinsic_name: INTRINSIC_CALLI_RANGE_DYN - sig: ecma.callithisrangedyn imm, v:in:top acc: out:top prefix: ecma format: [pref_op_imm_16_v_8] - properties: [call, not_compilable] + properties: [call] intrinsic_name: INTRINSIC_CALLI_THIS_RANGE_DYN - sig: ecma.supercall imm, v:in:top acc: inout:top diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 02de1eec57a01bce7602d7b850310efa5803d562..c61cb593d6bd53cf9759d1dc1eb7c32f3a96be3f 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -15,7 +15,6 @@ panda_promote_to_definitions(PANDA_ECMASCRIPT_ENABLE_RUNTIME_STAT) set(ECMA_SRC_DIR ${PANDA_ECMASCRIPT_PLUGIN_SOURCE}/runtime) -# ${BUILTIN_BRIDGE_SOURCE} is unused. Should be files deleted??? if(PANDA_TARGET_ARM32) SET(BUILTIN_BRIDGE_SOURCE ${ECMA_SRC_DIR}/arch/arm/builtin_bridge_arm.S) elseif(PANDA_TARGET_ARM64) @@ -201,6 +200,7 @@ set(ECMASCRIPT_SOURCES ${ECMA_SRC_DIR}/class_info_extractor.cpp ${ECMA_SRC_DIR}/compiler/ecmascript_runtime_interface.cpp + ${BUILTIN_BRIDGE_SOURCE} ${ECMA_SRC_DIR}/tooling/pt_ecmascript_extension.cpp ) diff --git a/runtime/asm_defines/asm_defines.def b/runtime/asm_defines/asm_defines.def index c1c0cd340ef10f080b2e772b199329a075e3cd5e..d4527b405e3562a55fa15a31cbde49ab29d3dd78 100644 --- a/runtime/asm_defines/asm_defines.def +++ b/runtime/asm_defines/asm_defines.def @@ -9,6 +9,7 @@ DEFINE_VALUE(JSTYPE_STRING, static_cast(panda::ecmascript::JSType::STRI DEFINE_VALUE(JSTYPE_JS_ARRAY, static_cast(panda::ecmascript::JSType::JS_ARRAY)) DEFINE_VALUE(JSTYPE_PROTOTYPE_HANDLER, static_cast(panda::ecmascript::JSType::PROTOTYPE_HANDLER)) DEFINE_VALUE(JSTYPE_TRANSITION_HANDLER, static_cast(panda::ecmascript::JSType::TRANSITION_HANDLER)) +DEFINE_VALUE(JSTYPE_JS_FUNCTION, static_cast(panda::ecmascript::JSType::JS_FUNCTION)) DEFINE_VALUE(ECMASTRING_MIX_LENGTH_OFFSET, panda::ecmascript::EcmaString::MIX_LENGTH_OFFSET) DEFINE_VALUE(JSFORINITERATOR_FAST_REMAINING_INDEX_OFFSET, panda::ecmascript::JSForInIterator::FAST_REMAINING_INDEX_OFFSET) DEFINE_VALUE(JSFORINITERATOR_REMAINING_KEYS_OFFSET, panda::ecmascript::JSForInIterator::REMAINING_KEYS_OFFSET) @@ -20,6 +21,7 @@ DEFINE_VALUE(JSHCLASS_BITFIELD_OFFSET, panda::ecmascript::JSHClass::BIT_FIELD_OF DEFINE_VALUE(JSHCLASS_BITFIELD_TYPE_MASK, panda::ecmascript::JSHClass::ObjectTypeBits::MaxValue()) DEFINE_VALUE(JSHCLASS_BITFIELD_TYPE_START_BIT, panda::ecmascript::JSHClass::ObjectTypeBits::START_BIT) DEFINE_VALUE(JSHCLASS_BITFIELD_IS_DICTIONARY_START_BIT, panda::ecmascript::JSHClass::IsDictionaryBit::START_BIT) +DEFINE_VALUE(JSHCLASS_BITFIELD_CONSTRUCTOR_START_BIT, panda::ecmascript::JSHClass::ConstructorBit::START_BIT) DEFINE_VALUE(JSHCLASS_BITFIELD_EXTENSIBLE_START_BIT, panda::ecmascript::JSHClass::ExtensibleBit::START_BIT) DEFINE_VALUE(JSHCLASS_BITFIELD_INLINED_PROPS_START_BITS_START_BIT, panda::ecmascript::JSHClass::InlinedPropsStartBits::START_BIT) DEFINE_VALUE(JSHCLASS_BITFIELD_INLINED_PROPS_START_BITS_MASK, panda::ecmascript::JSHClass::InlinedPropsStartBits::MaxValue()) diff --git a/runtime/bridge.h b/runtime/bridge.h new file mode 100644 index 0000000000000000000000000000000000000000..cebc91152532d5251efe32d68b8733e43bcb7fef --- /dev/null +++ b/runtime/bridge.h @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2021-2022 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. + */ + +#ifndef ECMASCRIPT_BRIDGE_BRIDGE_H +#define ECMASCRIPT_BRIDGE_BRIDGE_H + +#include "runtime/bridge/bridge.h" + +namespace panda { + +extern "C" DecodedTaggedValue CompiledCodeToBuiltinBridge(Method *, uint32_t, DecodedTaggedValue *, ...); + +} // namespace panda + +#endif // ECMASCRIPT_BRIDGE_BRIDGE_H diff --git a/runtime/builtins/builtins_function.cpp b/runtime/builtins/builtins_function.cpp index 0b243d4b8736f63c907ccf4ff4e61823403c23fa..16e053ed5008ad31a7ed8c5cb99e4658f622304b 100644 --- a/runtime/builtins/builtins_function.cpp +++ b/runtime/builtins/builtins_function.cpp @@ -25,7 +25,11 @@ namespace panda::ecmascript::builtins { static JSTaggedValue EvalHackReturnThis([[maybe_unused]] EcmaRuntimeCallInfo *argv) { - return argv->GetThis().GetTaggedValue(); + auto this_value = argv->GetThis().GetTaggedValue(); + if (this_value.IsNull() || this_value.IsUndefined()) { // workaround for sloppy call from compiled code + this_value = argv->GetThread()->GetGlobalObject(); + } + return this_value; } static JSTaggedValue EvalHackNop([[maybe_unused]] EcmaRuntimeCallInfo *argv) diff --git a/runtime/compiler/ecmascript_runtime_interface.cpp b/runtime/compiler/ecmascript_runtime_interface.cpp index 1107515ddb18b4c7d449150e6f18961ff1e31eb5..84202a1800461484adb7959457b62c2d4eaaacd6 100644 --- a/runtime/compiler/ecmascript_runtime_interface.cpp +++ b/runtime/compiler/ecmascript_runtime_interface.cpp @@ -43,4 +43,9 @@ size_t EcmaRuntimeInterface::GetEcmascriptLanguageExtensionSize() return 0; } +uint32_t EcmaRuntimeInterface::GetFunctionTargetOffset([[maybe_unused]] Arch arch) const +{ + return ecmascript::JSFunction::METHOD_OFFSET; +} + } // namespace panda diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index decfe58be201a316ae8bbb68c2485826be9e2cc7..b77f64e2e8bb25b9b80bd96f2e05958dd5d0a8dc 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -41,6 +41,8 @@ class EcmaRuntimeInterface : public PandaRuntimeInterface { ASSERT(panda::panda_file::IsDynamicLanguage(MethodCast(method)->GetClass()->GetSourceLang())); return std::string(static_cast(MethodCast(method))->GetFullName()); } + + uint32_t GetFunctionTargetOffset(Arch arch) const override; }; } // namespace panda diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 51c45fb92228b9e1ff640bca037ff754385bce63..d4d094d22583a02ae40622855627549817d3e584 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -1849,3 +1849,15 @@ intrinsics: codegen_func: CreateDynObjectSetClass use_thread: false clear_flags: [require_state, runtime_call] + +- name: DynCallCheck + space: ecmascript + class_name: Ecmascript.Intrinsics + method_name: CreateDynCallCheck + static: true + signature: + ret: void + args: [any] + codegen_func: CreateDynCallCheck + use_thread: false + clear_flags: [] diff --git a/runtime/ecma_runtime_call_info.h b/runtime/ecma_runtime_call_info.h index d5272093aa64f8e6ecc14f1c1cbea1356ef42d89..d3504ca6061024040e87ba5ebb50b0cab891e340 100644 --- a/runtime/ecma_runtime_call_info.h +++ b/runtime/ecma_runtime_call_info.h @@ -31,7 +31,19 @@ class EcmaRuntimeCallInfo { public: // For builtins interpreter call EcmaRuntimeCallInfo(JSThread *thread, uint32_t numArgs, interpreter::VRegister *args) - : thread_(thread), numArgs_(numArgs), gprArgs_(args, numArgs), stackArgs_(nullptr, static_cast(0)) + : thread_(thread), + numArgs_(numArgs), + gprArgs_(reinterpret_cast(args), numArgs), + stackArgs_(nullptr, static_cast(0)) + { + ASSERT(numArgs_ >= NUM_MANDATORY_JSFUNC_ARGS); + } + + EcmaRuntimeCallInfo(JSThread *thread, uint32_t numArgs, JSTaggedValue *gprArgs, JSTaggedValue *stackArgs) + : thread_(thread), + numArgs_(numArgs), + gprArgs_(gprArgs, GetGprArgsCount(numArgs)), + stackArgs_(stackArgs, GetStackArgsCount(numArgs)) { ASSERT(numArgs_ >= NUM_MANDATORY_JSFUNC_ARGS); } @@ -117,11 +129,25 @@ private: *reinterpret_cast(GetArgAddress(idx)) = tagged; } + static size_t GetGprArgsCount(uint32_t numArgs) + { + static_assert(arch::ExtArchTraits::NUM_GP_ARG_REGS >= 2); + size_t numArgRegs = arch::ExtArchTraits::NUM_GP_ARG_REGS - + 2; // first two regs are occupied by Method* and numArgs + size_t maxGprArgs = numArgRegs * ArchTraits::POINTER_SIZE / sizeof(JSTaggedValue); + return std::min(static_cast(numArgs), maxGprArgs); + } + + static size_t GetStackArgsCount(uint32_t numArgs) + { + return numArgs - GetGprArgsCount(numArgs); + } + private: JSThread *thread_; uint32_t numArgs_; - Span gprArgs_; - Span stackArgs_; + Span gprArgs_; + Span stackArgs_; }; } // namespace panda::ecmascript diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index 969c9c3ba46548c47ccfcb250c2a96781760c7a7..0bb9a57979e18fcc6f812d3fec30665f96eb11fa 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -14,6 +14,7 @@ */ #include "plugins/ecmascript/runtime/ecma_vm.h" +#include "plugins/ecmascript/runtime/bridge.h" #include "js_tagged_value.h" #include "mem/mark_word.h" @@ -609,6 +610,7 @@ JSMethod *EcmaVM::GetMethodForNativeFunction(const void *func) auto method = chunk_.New(n_wrapper); method->SetNativePointer(const_cast(func)); + method->SetCompiledEntryPoint(reinterpret_cast(CompiledCodeToBuiltinBridge)); nativeMethods_.push_back(method); return nativeMethods_.back(); } diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index f4bac392cbc9138e5c8e8097054417b0b26478e2..6c175a80f8a51d39b780cfbba6e2ce357bf790e0 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -231,25 +231,26 @@ public: ASSERT(JSTaggedValue(ret_value).IsException() == false); SetAccFromTaggedValue(ret_value); this->template MoveToNextInst(); - } else if (method->HasCompiledCode()) { - // AOT, JIT + return; + } + + JSFunction *js_function = JSFunction::Cast(this_func); + if (UNLIKELY(js_function->IsClassConstructor())) { + JSHandle error = + GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'"); + js_thread->SetException(error.GetTaggedValue()); + this->MoveToExceptionHandler(); + return; + } + + if (method->HasCompiledCode()) { // AOT, JIT EcmascriptEnvironment *prev_env = js_thread->GetEcmascriptEnv(); this->template CallCompiledCode(method); // Restore EcmascriptEnvironment if epilogue was not executed if (UNLIKELY(js_thread->HasPendingException())) { js_thread->SetEcmascriptEnv(prev_env); } - } else { - // Interpreter - JSFunction *js_function = JSFunction::Cast(this_func); - if (UNLIKELY(js_function->IsClassConstructor())) { - JSHandle error = - GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'"); - js_thread->SetException(error.GetTaggedValue()); - this->MoveToExceptionHandler(); - return; - } - + } else { // Interpreter EcmascriptEnvironment *prev_env = js_thread->GetEcmascriptEnv(); // Call stackless interpreter diff --git a/runtime/interpreter/interpreter-inl.h b/runtime/interpreter/interpreter-inl.h index a438eb5855ff38abc307161d72bd1105d08bf1ce..17942adc4679b6fc6fb94c7e4f152367ae18214b 100644 --- a/runtime/interpreter/interpreter-inl.h +++ b/runtime/interpreter/interpreter-inl.h @@ -96,6 +96,7 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *js_thread, JSTaggedValue const JSTaggedValue *args) { ASSERT(!js_thread->HasPendingException()); + ASSERT(!js_thread->IsCurrentFrameCompiled()); // Boundary frame expected for c2i call Method *method = ECMAObject::Cast(fn_object.GetHeapObject())->GetCallTarget(); ASSERT(method->GetNumVregs() == 0); @@ -150,7 +151,14 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, JSHandle ca Method *method = callTarget->GetCallTarget(); if (method->IsNative()) { - return EcmaInterpreter::ExecuteNative(thread, callTarget, numActualArgs, args); + if (!thread->IsCurrentFrameCompiled()) { + return ExecuteNative(thread, callTarget, numActualArgs, args); + } + ASSERT(!thread->HasPendingException()); + // TODO(vpukhov): create CFrame without i2c + TaggedValue ret_value = + method->InvokeDyn(thread, numActualArgs, reinterpret_cast(args)); + return JSTaggedValue(ret_value); } return ExecuteInvoke(thread, callTarget, numActualArgs, reinterpret_cast(args)); diff --git a/runtime/interpreter/js_frame-inl.h b/runtime/interpreter/js_frame-inl.h index f8f050f2e5a345bcab7ec2e2c192d7c6583dcd1b..7ea0f9b002c0374b6628793fc07e2afec3dad150 100644 --- a/runtime/interpreter/js_frame-inl.h +++ b/runtime/interpreter/js_frame-inl.h @@ -57,15 +57,10 @@ inline JSTaggedValue JSFrame::ExecuteNativeMethod(JSThread *js_thread, Frame *fr { ASSERT(js_thread == JSThread::GetCurrent()); - bool is_compiled = js_thread->IsCurrentFrameCompiled(); - js_thread->SetCurrentFrameIsCompiled(false); - EcmaRuntimeCallInfo call_info(js_thread, num_actual_args, &frame->GetVReg(0)); auto ecma_entry_point = reinterpret_cast(method->GetNativePointer()); JSTaggedValue ret_value = ecma_entry_point(&call_info); - js_thread->SetCurrentFrameIsCompiled(is_compiled); - return ret_value; } } // namespace panda::ecmascript diff --git a/runtime/js_function.h b/runtime/js_function.h index 7310250357c516dc3f35bb70b3794c5b1ed701e7..13a7031885dcc45512b14308baf9cc61e965f28e 100644 --- a/runtime/js_function.h +++ b/runtime/js_function.h @@ -286,6 +286,11 @@ public: ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, PROFILE_TYPE_INFO_OFFSET) ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, SIZE) + // NOLINTNEXTLINE(readability-magic-numbers) + static_assert(LEXICAL_ENV_OFFSET == 0x30); + // NOLINTNEXTLINE(readability-magic-numbers) + static_assert(CONSTANT_POOL_OFFSET == 0x50); + static constexpr uint32_t FUNCTION_KIND_BIT_NUM = 5; using FunctionKindBit = BitField; using StrictBit = FunctionKindBit::NextFlag; diff --git a/runtime/js_hclass.h b/runtime/js_hclass.h index 22ee5eaf46c46cb0753cf0e356abec9834689701..1fa45a580741f9812e8fffeab3b92a9102e137f3 100644 --- a/runtime/js_hclass.h +++ b/runtime/js_hclass.h @@ -210,8 +210,8 @@ public: static constexpr int TYPE_BITFIELD_NUM = 8; using ObjectTypeBits = BitField; // 7 using Unused1 = ObjectTypeBits::NextFlag; - using ConstrutorBit = Unused1::NextFlag; // 9 - using Unused2 = ConstrutorBit::NextFlag; // 10 + using ConstructorBit = Unused1::NextFlag; // 9 + using Unused2 = ConstructorBit::NextFlag; // 10 using ExtensibleBit = Unused2::NextFlag; using IsPrototypeBit = ExtensibleBit::NextFlag; using ElementRepresentationBits = IsPrototypeBit::NextField; // 3 means next 3 bit @@ -302,7 +302,7 @@ public: inline void SetConstructor(bool flag) const { - ConstrutorBit::Set(flag, GetBitFieldAddr()); + ConstructorBit::Set(flag, GetBitFieldAddr()); } inline void SetExtensible(bool flag) const @@ -758,7 +758,7 @@ public: inline bool IsConstructor() const { uint32_t bits = GetBitField(); - return ConstrutorBit::Decode(bits); + return ConstructorBit::Decode(bits); } inline bool IsBuiltinsCtor() const diff --git a/runtime/js_invoker.cpp b/runtime/js_invoker.cpp index 0ae06efe73b72adb11a5dfe41b4ab8974bbefef9..66984f9b627f3a1a1527b27d7da5b3e4b2fd5010 100644 --- a/runtime/js_invoker.cpp +++ b/runtime/js_invoker.cpp @@ -30,6 +30,32 @@ JSTaggedValue JsInvoker::Invoke([[maybe_unused]] JSThread *thread) UNREACHABLE(); } +extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t numArgs, JSTaggedValue *gprArgs, + JSTaggedValue *stackArgs) +{ + EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, numArgs, gprArgs, stackArgs); + + ASSERT(method->GetNativePointer() != nullptr); + + JSTaggedValue retValue = + reinterpret_cast(const_cast(method->GetNativePointer()))(&ecmaRuntimeCallInfo); + + if (thread->HasPendingException()) { + auto stack = StackWalker::Create(thread); + ASSERT(stack.IsCFrame() && stack.GetCFrame().IsNative()); + stack.NextFrame(); + // Native frames can handle exceptions as well + if (!stack.HasFrame() || !stack.IsCFrame() || stack.GetCFrame().IsNative()) { + return retValue.GetRawData(); + } + + FindCatchBlockInCFrames(thread, &stack, nullptr); + UNREACHABLE(); + } + + return retValue.GetRawData(); +} + JSTaggedValue InvokeJsFunction(JSThread *thread, const JSHandle &func, const JSHandle &obj, const JSHandle &newTgt, InternalCallParams *arguments) { diff --git a/runtime/runtime_sources.gn b/runtime/runtime_sources.gn index 31cb5e1121a66df6ede3469bfdab9011cd66bce4..5477ac554644753ae1b18aaf5f0051d75c33e3fc 100644 --- a/runtime/runtime_sources.gn +++ b/runtime/runtime_sources.gn @@ -175,7 +175,7 @@ srcs = [ # Should be files deleted??? #srcs_arm = [ "arch/arm/builtin_bridge_arm.S" ] -#srcs_arm64 = [ "arch/aarch64/builtin_bridge_aarch64.S" ] -#srcs_x86 = [ "arch/amd64/builtin_bridge_amd64.S" ] +srcs_arm64 = [ "arch/aarch64/builtin_bridge_aarch64.S" ] +srcs_x86 = [ "arch/amd64/builtin_bridge_amd64.S" ] runtime_yamls = [ "ecma_runtime.yaml" ] diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a4d8dfd613c189457ce9f25855b549b105515813..6e80c901870063343ad70a4cdfeec98048021e71 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -261,7 +261,10 @@ if (CMAKE_CROSSCOMPILING AND PANDA_TARGET_ARM64) # add_test_file_ecma(FILE "${CMAKE_CURRENT_SOURCE_DIR}/ecmascript-tests/js-bitops-bitwise-and.pa" COMPILER_OPTIONS --compiler-hotness-threshold=0) endif() -add_subdirectory(runtime) +# ARM32 is not supported for ecmascript +if(NOT PANDA_TARGET_ARM32) + add_subdirectory(runtime) +endif() if(PANDA_WITH_COMPILER) add_subdirectory(compiler) diff --git a/tests/checked/type_resolving.js b/tests/checked/type_resolving.js index 8db6aa56e3d4e79e29691ead85d1724fdaa3a7c2..160da8c041e6fbd13c2ddef44db3fc274cdf3028 100644 --- a/tests/checked/type_resolving.js +++ b/tests/checked/type_resolving.js @@ -70,8 +70,8 @@ //! check_aot.call(:Dec, 'DecDyn', 'f', /f64 +Sub/) //! check_aot.call(:Ldtrue, 'Ldtrue', '', /i64 +Constant +0x1/) //! check_aot.call(:Ldfalse, 'Ldfalse', '', /i64 +Constant +0x0/) -//! check_aot.call(:Ldnull, 'Ldnull', '', /i64 +Constant +0x2/) -//! check_aot.call(:Ldundefined, 'Ldundefined', '', /i64 +Constant +0xa/) +//! check_aot.call(:Ldnull, 'Ldnull', '', /any +Constant +0x2/) +//! check_aot.call(:Ldundefined, 'Ldundefined', '', /any +Constant +0xa/) //! check_aot.call(:Ldinfinity, 'Ldinfinity', '', /f64 +Constant +inf/) //! check_aot.call(:Ldnan, 'Ldnan', '', /f64 +Constant +nan/) //! diff --git a/tests/compiler/types_resolving_ecma_tests.cpp b/tests/compiler/types_resolving_ecma_tests.cpp index 9f7d78175b443d4e02b9d497dd652b871ba2dbf9..d4f9b225b4c78239c28e5789e8896f7c5a866ea4 100644 --- a/tests/compiler/types_resolving_ecma_tests.cpp +++ b/tests/compiler/types_resolving_ecma_tests.cpp @@ -183,15 +183,20 @@ TEST_F(TypeResolvingTest, LdConst) { using TaggedValue = panda::coretypes::TaggedValue; { - TestArray tests = {{ + TestArray tests = {{ {RuntimeInterface::IntrinsicId::INTRINSIC_LDTRUE, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 1U}, {RuntimeInterface::IntrinsicId::INTRINSIC_LDFALSE, AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE, 0U}, + }}; + TestLdConsts(tests); + } + { + TestArray tests = {{ {RuntimeInterface::IntrinsicId::INTRINSIC_LDHOLE, AnyBaseType::ECMASCRIPT_HOLE_TYPE, - TaggedValue::VALUE_HOLE}, + DataType::Any(TaggedValue::VALUE_HOLE)}, {RuntimeInterface::IntrinsicId::INTRINSIC_LDNULL, AnyBaseType::ECMASCRIPT_NULL_TYPE, - TaggedValue::VALUE_NULL}, + DataType::Any(TaggedValue::VALUE_NULL)}, {RuntimeInterface::IntrinsicId::INTRINSIC_LDUNDEFINED, AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE, - TaggedValue::VALUE_UNDEFINED}, + DataType::Any(TaggedValue::VALUE_UNDEFINED)}, }}; TestLdConsts(tests); } @@ -548,7 +553,7 @@ TEST_F(TypeResolvingTest, ResolveLoopPhi) } } ASSERT_TRUE(graph->RunPass()); - ASSERT_TRUE(graph->RunPass()); + ASSERT_TRUE(graph->RunPass(false)); GraphChecker(graph).Check(); auto &phi = INS(4); diff --git a/tests/runtime/irtoc/CMakeLists.txt b/tests/runtime/irtoc/CMakeLists.txt index 2fd563d70bee3be4e59760e456ed3cda0d7eeceb..7bd7dab1976d94d4ac3b7540fa00b489de4f97bf 100644 --- a/tests/runtime/irtoc/CMakeLists.txt +++ b/tests/runtime/irtoc/CMakeLists.txt @@ -1,8 +1,3 @@ -# We have issues for arm32 -if (PANDA_TARGET_ARM32) - return() -endif() - function(ecmascript_irtoc_interpreter_tests) set(prefix ARG) set(noValues)