diff --git a/compiler/codegen_intrinsics_ecmascript.cpp b/compiler/codegen_intrinsics_ecmascript.cpp index e50f98c7497d115fac99f3ba0726d8e7a446d97f..975677a2897b43773d739a50ff690afc7942c3c3 100644 --- a/compiler/codegen_intrinsics_ecmascript.cpp +++ b/compiler/codegen_intrinsics_ecmascript.cpp @@ -322,7 +322,7 @@ void Codegen::CreateDynObjectSetClass(IntrinsicInst *inst, [[maybe_unused]] Reg void Codegen::CreateDynCallCheck([[maybe_unused]] IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src) { - auto exit_label = CreateSlowPath(inst, EntrypointId::DEOPTIMIZE)->GetLabel(); + auto exit_label = CreateSlowPath(inst, DeoptimizeType::ANY_TYPE_CHECK)->GetLabel(); ScopedTmpReg tmp(GetEncoder(), ConvertDataType(DataType::UINT64, GetArch())); diff --git a/compiler/optimizer/code_generator/compiler_base_types.cpp b/compiler/optimizer/code_generator/compiler_base_types.cpp index fc35cdaf51d0e8a184fbe4203f76293127629f56..bf0b77ca8d8233629dada0a338e92ed8a5fb9489 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.cpp +++ b/compiler/optimizer/code_generator/compiler_base_types.cpp @@ -19,11 +19,13 @@ #include "compiler/optimizer/code_generator/codegen.h" #include "ir-dyn-base-types.h" #include "runtime/include/coretypes/tagged_value.h" +#include "profiling/profiling.h" namespace panda::compiler { static void CompareAnyTypeGenDouble(Encoder *enc, Reg dst, Reg src, bool is_int_possible, - LabelHolder::LabelId id = LabelHolder::INVALID_LABEL) + LabelHolder::LabelId not_number_label = LabelHolder::INVALID_LABEL, + LabelHolder::LabelId double_with_int_label = LabelHolder::INVALID_LABEL) { static constexpr uint16_t CMP_VAL = static_cast(UINT16_MAX) >> 1U; // 0x7fff static constexpr uint8_t SHIFT_VAL = coretypes::TaggedValue::TAG_BITS_SHIFT + 1; @@ -32,7 +34,8 @@ static void CompareAnyTypeGenDouble(Encoder *enc, Reg dst, Reg src, bool is_int_ LabelHolder::LabelId end_label = enc->CreateLabel(); - if (is_int_possible && id != LabelHolder::INVALID_LABEL) { + auto jump = not_number_label != LabelHolder::INVALID_LABEL; + if (is_int_possible && jump) { enc->EncodeShr(dst_ext, src, Imm(coretypes::TaggedValue::TAG_BITS_SHIFT)); enc->EncodeJump(end_label, dst_ext, Imm(coretypes::TaggedValue::TAG_INT >> coretypes::TaggedValue::TAG_BITS_SHIFT), Condition::EQ); @@ -44,10 +47,15 @@ static void CompareAnyTypeGenDouble(Encoder *enc, Reg dst, Reg src, bool is_int_ ScopedTmpReg reg_cmp(enc, TypeInfo(TypeInfo::TypeId::INT64)); enc->EncodeMov(reg_cmp, Imm(CMP_VAL)); // check if not Object and not Int - if (id == LabelHolder::INVALID_LABEL) { + if (!jump) { enc->EncodeCompare(dst, dst_ext, reg_cmp, Condition::LO); + } else if (double_with_int_label != LabelHolder::INVALID_LABEL) { + enc->EncodeJump(end_label, dst_ext, reg_cmp, Condition::LT); + auto bit = coretypes::TaggedValue::TAG_BITS_SIZE + coretypes::TaggedValue::TAG_BITS_SHIFT - 1; + enc->EncodeBitTestAndBranch(double_with_int_label, src, bit, true); + enc->EncodeJump(not_number_label); } else { - enc->EncodeJump(id, dst_ext, reg_cmp, Condition::GE); + enc->EncodeJump(not_number_label, dst_ext, reg_cmp, Condition::GE); } enc->BindLabel(end_label); } @@ -358,20 +366,55 @@ bool ecmascript::CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, Encod return false; } -bool ecmascript::AnyTypeCheckGen(const AnyTypeCheckInst *check_inst, EncodeVisitor *enc_v, LabelHolder::LabelId id) +static bool AnyTypeCheckGenCustomDeoptimization(Encoder *enc, Codegen *codegen, AnyTypeCheckInst *check_inst, Reg src) +{ + ScopedTmpReg tmp_reg(enc, TypeInfo(TypeInfo::TypeId::INT64)); + switch (check_inst->GetAnyType()) { + case AnyBaseType::ECMASCRIPT_INT_TYPE: { + auto id = + codegen->CreateSlowPath(check_inst, DeoptimizeType::NOT_SMALL_INT)->GetLabel(); + IsHasTagMaskGen(enc, tmp_reg, src, Imm(panda::coretypes::TaggedValue::TAG_INT), + Imm(panda::coretypes::TaggedValue::TAG_MASK), id); + return true; + } + case AnyBaseType::ECMASCRIPT_DOUBLE_TYPE: { + auto not_number = + codegen->CreateSlowPath(check_inst, DeoptimizeType::NOT_NUMBER)->GetLabel(); + auto double_with_int = + codegen->CreateSlowPath(check_inst, DeoptimizeType::DOUBLE_WITH_INT)->GetLabel(); + CompareAnyTypeGenDouble(enc, tmp_reg, src, check_inst->IsIntegerWasSeen(), not_number, double_with_int); + return true; + } + default: + return false; + } +} + +bool ecmascript::AnyTypeCheckGen(AnyTypeCheckInst *check_inst, EncodeVisitor *enc_v) { auto src = enc_v->GetCodegen()->ConvertRegister(check_inst->GetSrcReg(0), DataType::Type::INT64); Encoder *enc = enc_v->GetEncoder(); Codegen *codegen = enc_v->GetCodegen(); + + auto graph = codegen->GetGraph(); + auto custom_deoptimize = graph->IsAotMode() || graph->GetRuntime()->GetMethodProfile(graph->GetMethod(), true) != + profiling::INVALID_PROFILE; + if (custom_deoptimize && AnyTypeCheckGenCustomDeoptimization(enc, codegen, check_inst, src)) { + return true; + } + ScopedTmpReg tmp_reg(enc, TypeInfo(TypeInfo::TypeId::INT64)); + + auto id = codegen->CreateSlowPath(check_inst, DeoptimizeType::ANY_TYPE_CHECK)->GetLabel(); switch (check_inst->GetAnyType()) { case AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE: IsEqualToValGen(enc, tmp_reg, src, Imm(panda::coretypes::TaggedValue::VALUE_UNDEFINED), id); return true; - case AnyBaseType::ECMASCRIPT_INT_TYPE: + case AnyBaseType::ECMASCRIPT_INT_TYPE: { IsHasTagMaskGen(enc, tmp_reg, src, Imm(panda::coretypes::TaggedValue::TAG_INT), Imm(panda::coretypes::TaggedValue::TAG_MASK), id); return true; + } case AnyBaseType::ECMASCRIPT_OBJECT_TYPE: IsHasTagMaskGen(enc, tmp_reg, src, Imm(panda::coretypes::TaggedValue::TAG_OBJECT), Imm(panda::coretypes::TaggedValue::TAG_MASK), id); diff --git a/compiler/optimizer/code_generator/compiler_base_types.h b/compiler/optimizer/code_generator/compiler_base_types.h index 47d21c0699abe629eee388c59e1984e59738f80a..23106021a2eba2ea1e2cfef89442b485b10a2d0d 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.h +++ b/compiler/optimizer/code_generator/compiler_base_types.h @@ -30,7 +30,7 @@ namespace ecmascript { bool CompareAnyTypeGen(const CompareAnyTypeInst *cati, EncodeVisitor *enc_v); bool CastAnyTypeValueGen(const CastAnyTypeValueInst *cati, EncodeVisitor *enc_v); bool CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, EncodeVisitor *enc_v); -bool AnyTypeCheckGen(const AnyTypeCheckInst *check_inst, EncodeVisitor *enc_v, LabelHolder::LabelId id); +bool AnyTypeCheckGen(AnyTypeCheckInst *check_inst, EncodeVisitor *enc_v); } // namespace ecmascript } // namespace panda::compiler diff --git a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb index 63de114eca59d190347c6e4b75aaf4b06a48f5e7..dad342fd63cf0deb6b20c234b2ea5c7da7c45410 100644 --- a/compiler/templates/ecmascript_inst_builder_gen.cpp.erb +++ b/compiler/templates/ecmascript_inst_builder_gen.cpp.erb @@ -157,12 +157,13 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (with_speculative) { bool is_integer_seen = false; + bool is_type_profiled = false; % if has_profile && (inst.profile.properties.include?('operand_types_1') || inst.profile.properties.include?('operand_types_2')) - auto operand_type = GetProfilingAnyType(profile, bc_inst, <%= input_index %>, &is_integer_seen); + auto operand_type = GetProfilingAnyType(profile, bc_inst, <%= input_index %>, &is_integer_seen, &is_type_profiled); % else auto operand_type = compiler::AnyBaseType::UNDEFINED_TYPE; % end - input = BuildAnyTypeCheckInst(GetPc(bc_inst->GetAddress()), input, inst_save_state, operand_type, is_integer_seen); + input = BuildAnyTypeCheckInst(GetPc(bc_inst->GetAddress()), input, inst_save_state, operand_type, is_type_profiled, is_integer_seen); } inst->AppendInput(input); inst->AddInputType(DataType::ANY); @@ -218,13 +219,14 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (with_speculative) { bool is_integer_seen = false; + bool is_type_profiled = false; % if has_profile && (inst.profile.properties.include?('operand_types_1') || inst.profile.properties.include?('operand_types_2')) % idx = inst.profile.properties.include?('operand_types_2') ? 1 : 0 - auto operand_type = GetProfilingAnyType(profile, bc_inst, <%= idx %>, &is_integer_seen); + auto operand_type = GetProfilingAnyType(profile, bc_inst, <%= idx %>, &is_integer_seen, &is_type_profiled); % else auto operand_type = compiler::AnyBaseType::UNDEFINED_TYPE; % end - input = BuildAnyTypeCheckInst(GetPc(bc_inst->GetAddress()), input, inst_save_state, operand_type, is_integer_seen); + input = BuildAnyTypeCheckInst(GetPc(bc_inst->GetAddress()), input, inst_save_state, operand_type, is_type_profiled, is_integer_seen); } inst->AppendInput(input); diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index 823f23581a31cf44c99641c92572cc3ebd4ce27a..12c90b39aef8a8951bca64eea7f7b2ee30d54b80 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -807,10 +807,10 @@ public: << " v" << v0; uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Tonumber(this->GetJSThread(), value)); - UPDATE_UNARY_ARITH_PROFILE(value); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Tonumber(this->GetJSThread(), value)); + this->template MoveToNextInst(); } @@ -823,10 +823,10 @@ public: uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::NegDyn(this->GetJSThread(), value)); - UPDATE_UNARY_ARITH_PROFILE(value); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::NegDyn(this->GetJSThread(), value)); + this->template MoveToNextInst(); } @@ -839,10 +839,10 @@ public: uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::NotDyn(this->GetJSThread(), value)); - UPDATE_UNARY_ARITH_PROFILE(value); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::NotDyn(this->GetJSThread(), value)); + this->template MoveToNextInst(); } @@ -855,10 +855,10 @@ public: uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::IncDyn(this->GetJSThread(), value)); - UPDATE_UNARY_ARITH_PROFILE(value); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::IncDyn(this->GetJSThread(), value)); + this->template MoveToNextInst(); } @@ -871,10 +871,10 @@ public: uint64_t value = GetRegAsTaggedValue(v0).GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::DecDyn(this->GetJSThread(), value)); - UPDATE_UNARY_ARITH_PROFILE(value); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::DecDyn(this->GetJSThread(), value)); + this->template MoveToNextInst(); } @@ -1128,10 +1128,10 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Add2Dyn(this->GetJSThread(), left, right)); - UPDATE_BINARY_ARITH_PROFILE(left, right); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Add2Dyn(this->GetJSThread(), left, right)); + this->template MoveToNextInst(); } @@ -1144,10 +1144,10 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Sub2Dyn(this->GetJSThread(), left, right)); - UPDATE_BINARY_ARITH_PROFILE(left, right); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Sub2Dyn(this->GetJSThread(), left, right)); + this->template MoveToNextInst(); } @@ -1160,10 +1160,10 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Mul2Dyn(this->GetJSThread(), left, right)); - UPDATE_BINARY_ARITH_PROFILE(left, right); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Mul2Dyn(this->GetJSThread(), left, right)); + this->template MoveToNextInst(); } @@ -1176,10 +1176,10 @@ public: uint64_t left = GetRegAsTaggedValue(v0).GetRawData(); uint64_t right = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Div2Dyn(this->GetJSThread(), left, right)); - UPDATE_BINARY_ARITH_PROFILE(left, right); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Div2Dyn(this->GetJSThread(), left, right)); + this->template MoveToNextInst(); } @@ -1297,10 +1297,10 @@ public: uint64_t lhs = GetRegAsTaggedValue(v0).GetRawData(); uint64_t rhs = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Shl2Dyn(this->GetJSThread(), lhs, rhs)); - UPDATE_BINARY_ARITH_PROFILE(lhs, rhs); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Shl2Dyn(this->GetJSThread(), lhs, rhs)); + this->template MoveToNextInst(); } @@ -1314,10 +1314,10 @@ public: uint64_t lhs = GetRegAsTaggedValue(v0).GetRawData(); uint64_t rhs = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Shr2Dyn(this->GetJSThread(), lhs, rhs)); - UPDATE_BINARY_ARITH_PROFILE(lhs, rhs); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Shr2Dyn(this->GetJSThread(), lhs, rhs)); + this->template MoveToNextInst(); } @@ -1345,10 +1345,10 @@ public: uint64_t lhs = GetRegAsTaggedValue(v0).GetRawData(); uint64_t rhs = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::And2Dyn(this->GetJSThread(), lhs, rhs)); - UPDATE_BINARY_ARITH_PROFILE(lhs, rhs); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::And2Dyn(this->GetJSThread(), lhs, rhs)); + this->template MoveToNextInst(); } @@ -1362,10 +1362,10 @@ public: uint64_t lhs = GetRegAsTaggedValue(v0).GetRawData(); uint64_t rhs = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Or2Dyn(this->GetJSThread(), lhs, rhs)); - UPDATE_BINARY_ARITH_PROFILE(lhs, rhs); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Or2Dyn(this->GetJSThread(), lhs, rhs)); + this->template MoveToNextInst(); } @@ -1379,10 +1379,10 @@ public: uint64_t lhs = GetRegAsTaggedValue(v0).GetRawData(); uint64_t rhs = GetAccAsTaggedValue().GetRawData(); - INTRINSIC_CALL_CHECK_SETACC(intrinsics::Xor2Dyn(this->GetJSThread(), lhs, rhs)); - UPDATE_BINARY_ARITH_PROFILE(lhs, rhs); + INTRINSIC_CALL_CHECK_SETACC(intrinsics::Xor2Dyn(this->GetJSThread(), lhs, rhs)); + this->template MoveToNextInst(); } diff --git a/runtime/profiling/plugin_get_profiling_any_type.h b/runtime/profiling/plugin_get_profiling_any_type.h index a5ed31cae1d38490700b4200ec73ae4b487c1600..8dd3c4b4e5f8b228820f0f2b7d47557f04a35fc7 100644 --- a/runtime/profiling/plugin_get_profiling_any_type.h +++ b/runtime/profiling/plugin_get_profiling_any_type.h @@ -11,23 +11,47 @@ case panda::SourceLanguage::ECMASCRIPT: { case profiling::ProfilingKind::BINARY_ARITH: { panda::ecmascript::BinaryOperationProfile p(ecma_prof); type = p.GetOperandType(index); + auto other_operand_type = p.GetOperandType(1 - index); + if ((type & panda::ecmascript::ProfilingType::OBJECT) == panda::ecmascript::ProfilingType::OBJECT && + (other_operand_type & panda::ecmascript::ProfilingType::OBJECT) == + panda::ecmascript::ProfilingType::OBJECT) { + *is_type_profiled = true; + return compiler::AnyBaseType::UNDEFINED_TYPE; + } break; } default: LOG(FATAL, COMMON) << "Unknown profile"; } + + if (type == panda::ecmascript::ProfilingType(panda::ecmascript::ProfilingType::NONE)) { + return compiler::AnyBaseType::UNDEFINED_TYPE; + } + + *is_type_profiled = true; + auto is_int = (type & panda::ecmascript::ProfilingType::INTEGER) == panda::ecmascript::ProfilingType::INTEGER; + // ignore non number types to avoid compiled method destruction on deoptimization + if ((type & panda::ecmascript::ProfilingType::DOUBLE) == panda::ecmascript::ProfilingType::DOUBLE) { + *is_integer_seen = is_int; + return compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE; + } + + if (is_int) { + auto is_obj_seen = + (type & panda::ecmascript::ProfilingType::OBJECT) == panda::ecmascript::ProfilingType::OBJECT; + if (is_obj_seen) { + // return number type to avoid compiled method destruction on deoptimization + *is_integer_seen = true; + return compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE; + } + + return compiler::AnyBaseType::ECMASCRIPT_INT_TYPE; + } + switch (type) { case panda::ecmascript::ProfilingType::BOOLEAN: return compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE; - case panda::ecmascript::ProfilingType::INTEGER: - return compiler::AnyBaseType::ECMASCRIPT_INT_TYPE; - case panda::ecmascript::ProfilingType::DOUBLE: - *is_integer_seen = false; - return compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE; - case panda::ecmascript::ProfilingType::DOUBLE_INTEGER: - *is_integer_seen = true; - return compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE; default: return compiler::AnyBaseType::UNDEFINED_TYPE; } -} break; \ No newline at end of file +} break; diff --git a/tests/checked/CMakeLists.txt b/tests/checked/CMakeLists.txt index 769c10ab1372e91975372ed07cb99d104b10f986..c62e71364ab6f819bebeb7fb4106e3580be6bf5d 100644 --- a/tests/checked/CMakeLists.txt +++ b/tests/checked/CMakeLists.txt @@ -93,6 +93,10 @@ if (NOT PANDA_TARGET_ARM32) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/type_resolving.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/global_var.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/ecma_profiling.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/recompile_not_smi.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/recompile_double_with_int.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/recompile_not_number.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/recompile_undefined.js SUPPORT_RELEASE true) # there is flaky bug when turning on TSAN if (NOT PANDA_ENABLE_THREAD_SANITIZER) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/acc_after_deopt.js SUPPORT_RELEASE true) diff --git a/tests/checked/recompile_double_with_int.js b/tests/checked/recompile_double_with_int.js new file mode 100644 index 0000000000000000000000000000000000000000..5c88018433bce8f54b4b0db18e43ee7ba01be629 --- /dev/null +++ b/tests/checked/recompile_double_with_int.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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. + */ + +//! CHECKER Test deoptimization/recompilation starting with double_with_int deoptimization +//! RUN options: "--compiler-regex='_GLOBAL::sum' --no-async-jit=true --compiler-hotness-threshold=2", entry: "_GLOBAL::func_main_0" +//! EVENT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Compilation,_GLOBAL::sum/ +//! METHOD "_GLOBAL::func_sum_1" +//! PASS_AFTER "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! PASS_AFTER_NEXT "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE i" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" + +function sum(a, b) { + return a + b; +} + +sum(1.1, 2); +sum(1.1, 3); +sum(1.1, 3); +// sum was compiled +sum(1, 3); // double_with_int deoptimization +sum(1.2, 3); +sum(1.2, 3); +sum(1.2, 3); +// sum was compiled again +sum(null, 3); // not_number deoptimization +sum(1.2, 3); +sum(1, 3); +sum(1.2, 3); +sum(1.2, 3); diff --git a/tests/checked/recompile_not_number.js b/tests/checked/recompile_not_number.js new file mode 100644 index 0000000000000000000000000000000000000000..3923a2013f889469f1ef4a66704c4ab7a304a243 --- /dev/null +++ b/tests/checked/recompile_not_number.js @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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. + */ + +//! CHECKER Test deoptimization/recompilation starting with not_smi deoptimization after not_number argument +//! RUN options: "--compiler-regex='_GLOBAL::sum' --no-async-jit=true --compiler-hotness-threshold=2", entry: "_GLOBAL::func_main_0" +//! EVENT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Compilation,_GLOBAL::sum/ +//! METHOD "_GLOBAL::func_sum_1" +//! PASS_AFTER "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! PASS_AFTER_NEXT "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE i" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" + +function sum(a, b) { + return a + b; +} + +sum(1, 2); +sum(1, 3); +sum(1, 3); +// sum was compiled +sum(null, 3); // not_smi deoptimization +sum(1, 3); +sum(1, 3); +sum(1, 3); +// sum was compiled again +sum(1.1, 3); +sum(null, 3); // not_number deoptimization +sum(1, 3); +sum(1, 3); +sum(1, 3); +sum(1, 3); diff --git a/tests/checked/recompile_not_smi.js b/tests/checked/recompile_not_smi.js new file mode 100644 index 0000000000000000000000000000000000000000..6974dec869e326e703c333112ee5f3a9c84d3e90 --- /dev/null +++ b/tests/checked/recompile_not_smi.js @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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. + */ + +//! CHECKER Test deoptimization/recompilation starting with not_smi deoptimization +//! RUN options: "--compiler-regex='_GLOBAL::sum' --no-async-jit=true --compiler-hotness-threshold=2", entry: "_GLOBAL::func_main_0" +//! EVENT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT /Compilation,_GLOBAL::sum/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Deoptimization,_GLOBAL::func_sum_1/ +//! EVENT_NEXT_NOT /Compilation,_GLOBAL::sum/ +//! METHOD "_GLOBAL::func_sum_1" +//! PASS_AFTER "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" +//! PASS_AFTER_NEXT "IrBuilder" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE i" +//! INST_NEXT "AnyTypeCheck ECMASCRIPT_INT_TYPE" + +function sum(a, b) { + return a + b; +} + +sum(1, 2); +sum(1, 3); +sum(1, 3); +// sum was compiled +sum(1.1, 3); // not_smi deoptimization +sum(1, 3); +sum(1, 3); +sum(1, 3); +// sum was compiled again +sum(null, 3); // not_number deoptimization +sum(1, 3); +sum(1, 3); +sum(1, 3); +sum(1.1, 3); diff --git a/tests/checked/recompile_undefined.js b/tests/checked/recompile_undefined.js new file mode 100644 index 0000000000000000000000000000000000000000..e2bef8bfe27645d9f04f3f79efeac90bce385090 --- /dev/null +++ b/tests/checked/recompile_undefined.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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. + */ + +//! CHECKER Test deoptimization/recompilation which is caused due to incomplete profiling +//! RUN options: "--compiler-enable-osr=false --compiler-regex='_GLOBAL::test' --no-async-jit=true --compiler-hotness-threshold=2", entry: "_GLOBAL::func_main_0" +//! EVENT /Compilation,_GLOBAL::test/ +//! EVENT_NEXT /Deoptimization,_GLOBAL::func_test_1/ +//! EVENT_NEXT /Compilation,_GLOBAL::test/ +//! EVENT_NEXT_NOT /Deoptimization,_GLOBAL::func_test_1/ +//! METHOD "_GLOBAL::func_test_1" +//! PASS_AFTER "IrBuilder" +//! INST "AnyTypeCheck UNDEFINED" +//! INST_NEXT "AnyTypeCheck UNDEFINED" +//! PASS_AFTER_NEXT "IrBuilder" +//! INST_NOT "AnyTypeCheck UNDEFINED" + +var d = 1.1; + +function test() { + var s = 0; + for (let i = 0; i < 10; i += d) { + for (let j = 0; j < 10; j++) { + s += i; + } + } + return s; +} + +test(); +// test was compiled but profiling was not completed +// deduced type is int, but actual is double - deoptimize and recompile +test(); +test();