diff --git a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h index 7455e257102db16590d278144ebdac980c45a3d0..a16e515108fcb0e90523e94abe027f3b995b71de 100644 --- a/compiler/ecmascript_extensions/ecmascript_compiler_interface.h +++ b/compiler/ecmascript_extensions/ecmascript_compiler_interface.h @@ -88,4 +88,9 @@ virtual GlobalVarInfo GetGlobalVarInfo([[maybe_unused]] MethodPtr method, [[mayb return {GlobalVarInfo::Type::DEFAULT, 0}; } +virtual uintptr_t GetGlobalConstStringOffsetForAnyType([[maybe_unused]] compiler::AnyBaseType type, + [[maybe_unused]] Arch arch) const +{ + return 0; +} #endif // PANDA_COMPILER_ECMASCRIPT_COMPILER_INTERFACE_H \ No newline at end of file diff --git a/compiler/ecmascript_extensions/ecmascript_irtoc_interface.h b/compiler/ecmascript_extensions/ecmascript_irtoc_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..bfe30ebde16f6844a803388ea6f581af5fc07d11 --- /dev/null +++ b/compiler/ecmascript_extensions/ecmascript_irtoc_interface.h @@ -0,0 +1,60 @@ +/* + * 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 PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_H +#define PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_H + +size_t GetGlobalConstStringOffsetForAnyType(compiler::AnyBaseType type, Arch arch) const override +{ + auto global_const_array_offset = + cross_values::GetJsthreadGlobalConstantsOffset(arch) + cross_values::GetGlobalConstConstantsOffset(arch); + switch (type) { + case compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::UNDEFINED_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::STRING_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_INT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::NUMBER_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::NUMBER_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::SYMBOL_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::FUNCTION_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::BOOLEAN_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_NULL_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::OBJECT_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::BIGINT_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::OBJECT_STRING_INDEX); + default: + UNREACHABLE(); + } + return 0; +} + +#endif // PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_H \ No newline at end of file diff --git a/compiler/ecmascript_extensions/ecmascript_irtoc_interface_includes.h b/compiler/ecmascript_extensions/ecmascript_irtoc_interface_includes.h new file mode 100644 index 0000000000000000000000000000000000000000..e28a2ce937dce836de4f31a00e2c7c7df16e9ccf --- /dev/null +++ b/compiler/ecmascript_extensions/ecmascript_irtoc_interface_includes.h @@ -0,0 +1,22 @@ +/* + * 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 PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_INCLUDES_H +#define PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_INCLUDES_H + +#include "plugins/ecmascript/runtime/global_env_constants.h" +#include "plugins/ecmascript/runtime/js_thread.h" + +#endif // PANDA_COMPILER_ECMASCRIPT_IRTOC_INTERFACE_INCLUDES_H \ No newline at end of file diff --git a/compiler/intrinsics_inline_ecmascript.inl b/compiler/intrinsics_inline_ecmascript.inl index 07f009200be77def1484677495110a49588b6249..97e6c1df73418f08a8211c4a877e36e702f7ecb1 100644 --- a/compiler/intrinsics_inline_ecmascript.inl +++ b/compiler/intrinsics_inline_ecmascript.inl @@ -152,4 +152,8 @@ case RuntimeInterface::IntrinsicId::INTRINSIC_ST_OBJ_BY_NAME: { } case RuntimeInterface::IntrinsicId::INTRINSIC_RESOLVE_ALLOC_RESULT: { return InlineResolveAllocResult(intrinsic); +} +case RuntimeInterface::IntrinsicId::INTRINSIC_TYPEOF_DYN: { + ASSERT(types_.size() == 1); + return InlineTypeOf(intrinsic); } \ No newline at end of file diff --git a/compiler/intrinsics_type_resolving_ecmascript.cpp b/compiler/intrinsics_type_resolving_ecmascript.cpp index d10331f15554879c30395dcead2e7600088a56de..6443e5acffb57221d8c18d3dbef94d0132bdbccf 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.cpp +++ b/compiler/intrinsics_type_resolving_ecmascript.cpp @@ -99,6 +99,23 @@ bool TypesResolving::InlineLdNan(IntrinsicInst *intrinsic) return InlineLdConstant(intrinsic, AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, TaggedValue::VALUE_NAN); } +bool TypesResolving::InlineTypeOf(IntrinsicInst *intrinsic) +{ + auto any_type = intrinsic->GetInput(0).GetInst(); + if (any_type->GetOpcode() != Opcode::AnyTypeCheck) { + return false; + } + auto type = any_type->CastToAnyTypeCheck()->GetAnyType(); + + if (type == AnyBaseType::UNDEFINED_TYPE) { + return false; + } + auto any_name = GetGraph()->CreateInstGetAnyTypeName(DataType::ANY, intrinsic->GetPc()); + any_name->SetAnyType(type); + intrinsic->InsertBefore(any_name); + return true; +} + void TypesResolving::CreateCompareClass(uint32_t pc, Inst *get_cls_inst, RuntimeInterface::ClassPtr receiver, BasicBlock *load_bb) { diff --git a/compiler/intrinsics_type_resolving_ecmascript.inl.h b/compiler/intrinsics_type_resolving_ecmascript.inl.h index 8505d54b5bf95e572e945bdb242256bd9bdd5515..ae5ec59de539394ffa9f83b3773074868f705147 100644 --- a/compiler/intrinsics_type_resolving_ecmascript.inl.h +++ b/compiler/intrinsics_type_resolving_ecmascript.inl.h @@ -27,6 +27,7 @@ bool InlineLdNan(IntrinsicInst *intrinsic); bool InlineLdObjByName(IntrinsicInst *intrinsic); bool InlineStObjByName(IntrinsicInst *intrinsic); bool InlineResolveAllocResult(IntrinsicInst *intrinsic); +bool InlineTypeOf(IntrinsicInst *intrinsic); private: template diff --git a/compiler/optimizer/code_generator/compiler_base_types.cpp b/compiler/optimizer/code_generator/compiler_base_types.cpp index ace74e71c2a903e13f3626b40c34fc5d7a38df44..937a7a68902c53df82e7ce7e7a944db9f93f0eab 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.cpp +++ b/compiler/optimizer/code_generator/compiler_base_types.cpp @@ -156,15 +156,73 @@ static void CompareAnyTypeGenObject(Encoder *enc, const Reg &dst, const Reg &src enc->BindLabel(label_false); } +static void CompareOrCheckAnyTypeCallable(Codegen *codegen, Encoder *enc, const Reg &dst, const Reg &src, + LabelHolder::LabelId id = LabelHolder::INVALID_LABEL) +{ + auto label_false = enc->CreateLabel(); + auto arch = codegen->GetArch(); + Reg res_reg = dst; + bool need_temp = (dst.GetId() == src.GetId()); + ScopedTmpRegLazy tmp_dst(enc); + if (need_temp) { + tmp_dst.AcquireIfInvalid(); + res_reg = tmp_dst.GetReg().As(codegen->ConvertDataType(DataType::ANY, arch)); + } + + if (id == LabelHolder::INVALID_LABEL) { + enc->EncodeMov(res_reg, Imm(0)); + } + LabelHolder::LabelId label = (id == LabelHolder::INVALID_LABEL) ? label_false : id; + CheckAnyTypeGenObject(enc, src, label); + ScopedTmpReg tmp_reg(enc, codegen->ConvertDataType(DataType::REFERENCE, arch)); + + enc->EncodeLdr(tmp_reg, false, MemRef(src, codegen->GetRuntime()->GetObjClassOffset(arch))); + Reg tmp32_reg = tmp_reg.GetReg().As(TypeInfo(TypeInfo::TypeId::INT32)); + enc->EncodeLdr(tmp32_reg, false, MemRef(tmp_reg, codegen->GetRuntime()->GetBaseClassFlagsOffset(arch))); + auto is_callable_mask = codegen->GetRuntime()->GetCallableMask(); + enc->EncodeJumpTest(label, tmp32_reg, Imm(is_callable_mask), Condition::TST_EQ); + if (id == LabelHolder::INVALID_LABEL) { + enc->EncodeMov(res_reg, Imm(1U)); + enc->BindLabel(label_false); + if (need_temp) { + enc->EncodeMov(dst, res_reg); + } + } +} + // dst = (IsHeapObject() and ! object.type, type) static void CompareAnyTypeGenObjectType(Codegen *codegen, Encoder *enc, const Reg &dst, const Reg &src, uint32_t type, Condition fail_cc = Condition::NE) { + Reg res_reg = dst; + auto arch = codegen->GetArch(); + bool need_temp = (dst.GetId() == src.GetId()); + ScopedTmpRegLazy tmp_reg(enc); + if (need_temp) { + tmp_reg.AcquireIfInvalid(); + res_reg = tmp_reg.GetReg().As(codegen->ConvertDataType(DataType::ANY, arch)); + } auto label_false = enc->CreateLabel(); - enc->EncodeMov(dst, Imm(0)); + enc->EncodeMov(res_reg, Imm(0)); CheckAnyTypeGenObjectType(codegen, enc, src, type, label_false, fail_cc); - enc->EncodeMov(dst, Imm(1U)); + enc->EncodeMov(res_reg, Imm(1U)); enc->BindLabel(label_false); + if (need_temp) { + enc->EncodeMov(dst, res_reg); + } +} + +bool ecmascript::GetAnyTypeNameGen(const GetAnyTypeNameInst *inst, EncodeVisitor *enc_v) +{ + Encoder *enc = enc_v->GetEncoder(); + Codegen *codegen = enc_v->GetCodegen(); + auto dst = codegen->ConvertRegister(inst->GetDstReg(), DataType::Type::ANY); + + auto graph = codegen->GetGraph(); + auto offset = graph->GetRuntime()->GetGlobalConstStringOffsetForAnyType(inst->GetAnyType(), graph->GetArch()); + enc->EncodeLdr(dst, false, MemRef(codegen->ThreadReg(), offset)); + + return true; } bool ecmascript::CompareAnyTypeGen(const CompareAnyTypeInst *cati, EncodeVisitor *enc_v) @@ -216,6 +274,12 @@ bool ecmascript::CompareAnyTypeGen(const CompareAnyTypeInst *cati, EncodeVisitor CompareAnyTypeGenObjectType(codegen, enc, dst, src, cross_values::GetJstypeJsArray(codegen->GetArch()), Condition::LE); return true; + case AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + CompareAnyTypeGenObjectType(codegen, enc, dst, src, cross_values::GetJstypeJsFunction(codegen->GetArch())); + return true; + case AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + CompareOrCheckAnyTypeCallable(codegen, enc, dst, src); + return true; case AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: { CompareAnyTypeGenBool(enc, dst, src); return true; @@ -294,6 +358,8 @@ bool ecmascript::CastAnyTypeValueGen(const CastAnyTypeValueInst *cati, EncodeVis case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: + case AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + case AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: case AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE: { enc->EncodeMov(dst, src); return true; @@ -344,6 +410,8 @@ bool ecmascript::CastValueToAnyTypeGen(const CastValueToAnyTypeInst *cvai, Encod case AnyBaseType::ECMASCRIPT_ARRAY_TYPE: case AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: + case AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + case AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: case AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE: // With current boxing scheme, we must guarantee that boxed objects have upper 16 bits set to 0. // Boxed values are no less than 64 bits wide (to hold double-precision floating point numbers). @@ -489,6 +557,9 @@ bool ecmascript::AnyTypeCheckGen(AnyTypeCheckInst *check_inst, EncodeVisitor *en case AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: CheckAnyTypeGenObjectType(codegen, enc, src, cross_values::GetJstypeJsFunction(codegen->GetArch()), id); return true; + case AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + CompareOrCheckAnyTypeCallable(codegen, enc, INVALID_REGISTER, src, id); + return true; default: return false; } diff --git a/compiler/optimizer/code_generator/compiler_base_types.h b/compiler/optimizer/code_generator/compiler_base_types.h index 114ac3c2ebe3731e14b47b0f07ad87545fd5c0a4..4c79d9d43fc47cd74843b999d8c789c9e730d6a7 100644 --- a/compiler/optimizer/code_generator/compiler_base_types.h +++ b/compiler/optimizer/code_generator/compiler_base_types.h @@ -24,6 +24,7 @@ class CompareAnyTypeInst; class CastAnyTypeValueInst; class CastValueToAnyTypeInst; class AnyTypeCheckInst; +class GetAnyTypeNameInst; class FixedInputsInst2; class EncodeVisitor; @@ -38,6 +39,7 @@ bool DynamicCallCheckGen(FixedInputsInst2 *check_inst, EncodeVisitor *enc_v); bool LoadConstantPoolGen(const Inst *inst, EncodeVisitor *enc_v); bool LoadLexicalEnvGen(const Inst *inst, EncodeVisitor *enc_v); bool LoadStringDynamicGen(Inst *inst, EncodeVisitor *enc_v); +bool GetAnyTypeNameGen(const GetAnyTypeNameInst *inst, EncodeVisitor *enc_v); } // namespace ecmascript } // namespace panda::compiler diff --git a/compiler/optimizer/ir/dyn_datatype.h b/compiler/optimizer/ir/dyn_datatype.h index 498e730a8966bf1c1f7566e97dd96a71a1f45113..292d3149881f4981a0a635a6a6b3d77c0efeaf87 100644 --- a/compiler/optimizer/ir/dyn_datatype.h +++ b/compiler/optimizer/ir/dyn_datatype.h @@ -74,6 +74,8 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: return true; default: break; @@ -88,6 +90,8 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa case panda::compiler::AnyBaseType::ECMASCRIPT_TRANSITION_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_PROTOTYPE_HANDLER_TYPE: case panda::compiler::AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: return true; default: break; @@ -122,6 +126,18 @@ static inline std::optional IsAnyTypeCanBeSubtypeOf(panda::compiler::AnyBa break; } break; + case panda::compiler::AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + switch (type) { + case panda::compiler::AnyBaseType::ECMASCRIPT_OBJECT_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + case panda::compiler::AnyBaseType::ECMASCRIPT_FUNCTION_TYPE: + return std::nullopt; + default: + break; + } + break; default: break; } diff --git a/ecmascript_plugin_options.yaml b/ecmascript_plugin_options.yaml index 104f39aefddf8844da73ffb2ae2ccf005e3c58bb..63d3aac118c8e42767303aba59bb31a848656ed1 100644 --- a/ecmascript_plugin_options.yaml +++ b/ecmascript_plugin_options.yaml @@ -30,6 +30,8 @@ main_header_path: plugins/ecmascript/compiler/extensions.h header_path_implementation_codegen: plugins/ecmascript/compiler/ecmascript_extensions/ecmascript_codegen_extensions.h header_path_compiler_interface_extension: plugins/ecmascript/compiler/ecmascript_extensions/ecmascript_compiler_interface.h + header_path_irtoc_interface_extension: plugins/ecmascript/compiler/ecmascript_extensions/ecmascript_irtoc_interface.h + header_path_irtoc_interface_extension_includes: plugins/ecmascript/compiler/ecmascript_extensions/ecmascript_irtoc_interface_includes.h header_path_compiler_inst_builder_extension: plugins/ecmascript/compiler/optimizer/ir_builder/ecmascript_inst_builder.h function_codegen_prologue: GenerateEcmascriptEnvInPrologue function_codegen_epilogue: GenerateEcmascriptEnvInEpilogue @@ -38,6 +40,7 @@ compiler_base_types: header_path_implementation_codegen: plugins/ecmascript/compiler/optimizer/code_generator/compiler_base_types.h func_compare_implementation_codegen: panda::compiler::ecmascript::CompareAnyTypeGen + func_get_name_implementation_codegen: panda::compiler::ecmascript::GetAnyTypeNameGen func_cast_implementation_codegen: panda::compiler::ecmascript::CastAnyTypeValueGen func_cast_to_any_implementation_codegen: panda::compiler::ecmascript::CastValueToAnyTypeGen func_any_type_check_implementation_codegen: panda::compiler::ecmascript::AnyTypeCheckGen @@ -65,6 +68,7 @@ SPECIAL_INDEXED_TYPE: panda::compiler::DataType::Type::REFERENCE BOOLEAN_TYPE: panda::compiler::DataType::Type::BOOL FUNCTION_TYPE: panda::compiler::DataType::Type::REFERENCE + CALLABLE_TYPE: panda::compiler::DataType::Type::REFERENCE BIGINT_TYPE: panda::compiler::DataType::Type::REFERENCE Intrinsics: intrinsic_inline_inl: plugins/ecmascript/compiler/intrinsics_inline_ecmascript.inl diff --git a/irtoc_scripts/common.irt b/irtoc_scripts/common.irt index 9c02ac2eaa5297b6a67651cd72b81ecf35a5e5de..9d5357ee5698f11f80869906b8d2766a6a5c7838 100644 --- a/irtoc_scripts/common.irt +++ b/irtoc_scripts/common.irt @@ -215,7 +215,58 @@ scoped_macro(:map_ic_slot) do |this_func, ic_slot| mapping := Load(method_ptr, "JSMETHOD_IC_MAPPING_OFFSET").ptr Load(mapping, ic_slot).u8 end +macro(:cmpanyi32) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_INT_TYPE").b +end + +macro(:cmpanyf64) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_DOUBLE_TYPE").b +end + +macro(:cmpanyheapobj) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE").b +end + +macro(:cmpanyarr) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_ARRAY_TYPE").b +end + +macro(:cmpanyhole) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_HOLE_TYPE").b +end + +macro(:cmpanyundefined) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE").b +end + +macro(:cmpanystring) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_STRING_TYPE").b +end + +macro(:cmpanyspecialindexedobj) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_SPECIAL_INDEXED_TYPE").b +end macro(:cmpanysymbol) do |arg| CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_SYMBOL_TYPE").b +end + +macro(:cmpanynull) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_NULL_TYPE").b +end + +macro(:cmpanybool) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE").b +end + +macro(:cmpanybigint) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_BIGINT_TYPE").b +end + +macro(:cmpanyfunction) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_FUNCTION_TYPE").b +end + +macro(:cmpanycallable) do |arg| + CompareAnyType(arg).AnyType("AnyBaseType::ECMASCRIPT_CALLABLE_TYPE").b end \ No newline at end of file diff --git a/irtoc_scripts/interpreter_handlers.irt b/irtoc_scripts/interpreter_handlers.irt index 7653d023beb2dcaa9ed2237ba39fb0c44f8aef4c..053519dd60da26e57f2333a53c4190088a0fc870 100644 --- a/irtoc_scripts/interpreter_handlers.irt +++ b/irtoc_scripts/interpreter_handlers.irt @@ -1875,3 +1875,71 @@ function(:FastPathStGlobalVar, end ###################################################### +# TYPE_OF +# +macro(:handle_ecma_typeof) do |value| + IfImm(cmpanyf64(value).b).Imm(0).NE.b { + double := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_DOUBLE_TYPE").any + Goto(:Exit) + } + IfImm(cmpanyi32(value).b).Imm(0).NE.b { + int := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_INT_TYPE").any + Goto(:Exit) + } + IfImm(cmpanyundefined(value)).Imm(0).CC(:CC_NE).b { + undefined := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE").any + Goto(:Exit) + } + IfImm(cmpanybool(value)).Imm(0).CC(:CC_NE).b { + boolean := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE").any + Goto(:Exit) + } + IfImm(cmpanynull(value)).Imm(0).CC(:CC_NE).b { + null := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_NULL_TYPE").any + Goto(:Exit) + } + IfImm(cmpanyheapobj(value)).Imm(0).CC(:CC_NE).b { + IfImm(cmpanystring(value)).Imm(0).CC(:CC_NE).b { + string := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_STRING_TYPE").any + Goto(:Exit) + } + IfImm(cmpanysymbol(value)).Imm(0).CC(:CC_NE).b { + symbol := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_SYMBOL_TYPE").any + Goto(:Exit) + } + IfImm(cmpanybigint(value)).Imm(0).CC(:CC_NE).b { + big_int := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_BIGINT_TYPE").any + Goto(:Exit) + } + IfImm(cmpanycallable(value)).Imm(0).CC(:CC_NE).b { + function := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_CALLABLE_TYPE").any + Goto(:Exit) + } + object := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE").any + Goto(:Exit) + } +undefined_string := GetAnyTypeName().AnyType("AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE").any +Label(:Exit) + Phi(double, int, undefined, boolean, null, string, symbol, big_int, function, object, undefined_string).any +end + +function(:EcmaTypeofdyn, params: { 'value'=>'any'}, mode: [:Interpreter, :DynamicMethod, :DynamicStub], lang: 'ECMASCRIPT', regmap: $panda_regmap, enable_builder: true) do + res := handle_ecma_typeof(value) + Return(res).any +end + +function(:FastTypeOfDyn, + params: {value: 'any'}, + mode: [:FastPath, :DynamicMethod, :DynamicStub], + regmap: $full_regmap, + lang: 'ECMASCRIPT', + regalloc_set: RegMask.new($full_regmap, :arg0, :arg1) + $panda_callees_mask - $panda_regmap) do + # Arm32 is not supported + if Options.arch == :arm32 + Intrinsic(:UNREACHABLE).Terminator.void + next + end + + res := handle_ecma_typeof(value) + Return(res).any +end \ No newline at end of file diff --git a/isa/isa.yaml b/isa/isa.yaml index 86d9712f5a45ec4033cfb203ba85798fab77d108..69e7a94434a1fbeb7103416e9977b8c179135395 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -55,6 +55,9 @@ profiles: - name: UnaryArith size: 2 properties: [operand_types_1] + - name: TypeOf + size: 2 + properties: [operand_types_1] - name: ObjByIndex size: 1 properties: [] @@ -158,8 +161,10 @@ groups: - sig: ecma.typeofdyn acc: inout:top prefix: ecma - format: [pref_op_none] + format: [pref_op_none_prof_16] + properties: [inlinable] intrinsic_name: INTRINSIC_TYPEOF_DYN + profile: TypeOf - sig: ecma.ldlexenvdyn acc: out:top diff --git a/runtime/asm_defines/asm_defines.def b/runtime/asm_defines/asm_defines.def index 72588841c2ff958b6788b6e66496cf9c9b9e4de1..18eca2de37927a80e31e8fefb9c9f86049c1ff7c 100644 --- a/runtime/asm_defines/asm_defines.def +++ b/runtime/asm_defines/asm_defines.def @@ -96,6 +96,7 @@ DEFINE_VALUE(IC_HANDLER_HANDLER_KIND_FIELD, static_cast(panda::ecmascr DEFINE_VALUE(HCLASS_DATA_OFFSET, HClass::GetDataOffset()) DEFINE_VALUE(JSMETHOD_IC_MAPPING_OFFSET, panda::ecmascript::JSMethod::GetICMappingOffset()) DEFINE_VALUE(HCLASS_IS_BUILTINS_CTOR_MASK, HClass::IS_BUILTINS_CTOR) +DEFINE_VALUE(JSTHREAD_GLOBAL_CONSTANTS_OFFSET, panda::ecmascript::JSThread::GetGlobalConstantsOffset()) DEFINE_VALUE(JSTHREAD_GLOBAL_OBJECT_OFFSET, panda::ecmascript::JSThread::GetGlobalObjectOffset()) DEFINE_VALUE(THREAD_PROPERTIES_CACHE_OFFSET, panda::ecmascript::JSThread::GetPropertiesCacheOffset()) DEFINE_VALUE(PROPERTIES_CACHE_LENGTH, panda::ecmascript::PropertiesCache::CACHE_LENGTH) @@ -131,4 +132,5 @@ DEFINE_VALUE(FUNCTION_KIND_DERIVED_CTOR, panda::ecmascript::FunctionKind::DERIVE DEFINE_VALUE(TAGGED_TYPE_SIZE, panda::ecmascript::JSTaggedValue::TaggedTypeSize()) DEFINE_VALUE(ECMA_VM_GLOBAL_ENV_OFFSET, panda::ecmascript::EcmaVM::GetGlobalEnvOffset()) DEFINE_VALUE(GLOBAL_ENV_HEADER_SIZE, panda::ecmascript::GlobalEnv::HEADER_SIZE) -DEFINE_VALUE(GLOBAL_ENV_EMPTY_ARRAY_INDEX, panda::ecmascript::GlobalEnv::EMPTY_ARRAY_OBJECT_INDEX) \ No newline at end of file +DEFINE_VALUE(GLOBAL_ENV_EMPTY_ARRAY_INDEX, panda::ecmascript::GlobalEnv::EMPTY_ARRAY_OBJECT_INDEX) +DEFINE_VALUE(GLOBAL_CONST_CONSTANTS_OFFSET, panda::ecmascript::GlobalEnvConstants::GetConstantsOffset()) \ No newline at end of file diff --git a/runtime/compiler/ecmascript_runtime_interface.cpp b/runtime/compiler/ecmascript_runtime_interface.cpp index cfa8189fabd9d0d30b286f9a99028070e8d6e858..bae9542480df5140a8200242280da88bb3ee13ba 100644 --- a/runtime/compiler/ecmascript_runtime_interface.cpp +++ b/runtime/compiler/ecmascript_runtime_interface.cpp @@ -165,6 +165,37 @@ Expected EcmaRuntimeInterface::AddProfile(std::string_view f return true; } +inline compiler::AnyBaseType GetTypeOfType(panda::ecmascript::ProfilingTypeOfBits::Type type, bool *is_integer_seen, + bool *is_type_profiled) +{ + if (type == panda::ecmascript::ProfilingTypeOfBits::NONE) { + return compiler::AnyBaseType::UNDEFINED_TYPE; + } + + *is_type_profiled = true; + switch (type) { + case panda::ecmascript::ProfilingTypeOfBits::NUMBER: { + *is_integer_seen = true; + return compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE; + } + case panda::ecmascript::ProfilingTypeOfBits::SYMBOL: + return compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE; + case panda::ecmascript::ProfilingTypeOfBits::BOOLEAN: + return compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE; + case panda::ecmascript::ProfilingTypeOfBits::STRING: + return compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE; + case panda::ecmascript::ProfilingTypeOfBits::FUNCTION: + return compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE; + case panda::ecmascript::ProfilingTypeOfBits::UNDEFINED: + return compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE; + case panda::ecmascript::ProfilingTypeOfBits::BIGINT: + return compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE; + default: + return compiler::AnyBaseType::UNDEFINED_TYPE; + } + return compiler::AnyBaseType::UNDEFINED_TYPE; +} + compiler::AnyBaseType EcmaRuntimeInterface::GetProfilingAnyType(RuntimeInterface::BytecodeProfile profile, const BytecodeInstruction *bc_inst, unsigned index, bool *is_integer_seen, bool *is_type_profiled) @@ -173,6 +204,10 @@ compiler::AnyBaseType EcmaRuntimeInterface::GetProfilingAnyType(RuntimeInterface auto ecma_prof = reinterpret_cast(profile); panda::ecmascript::ProfilingTypeBits::Type type = panda::ecmascript::ProfilingTypeBits::NONE; switch (kind) { + case profiling::ProfilingKind::TYPE_OF: { + panda::ecmascript::TypeOfOperationProfile p(ecma_prof); + return GetTypeOfType(p.GetOperandType(index).GetType(), is_integer_seen, is_type_profiled); + } case profiling::ProfilingKind::UNARY_ARITH: { panda::ecmascript::UnaryOperationProfile p(ecma_prof); type = p.GetOperandType(index).GetType(); @@ -193,7 +228,6 @@ compiler::AnyBaseType EcmaRuntimeInterface::GetProfilingAnyType(RuntimeInterface default: LOG(FATAL, COMMON) << "Unknown profile"; } - if (type == panda::ecmascript::ProfilingTypeBits::NONE) { return compiler::AnyBaseType::UNDEFINED_TYPE; } @@ -244,6 +278,46 @@ compiler::AnyBaseType EcmaRuntimeInterface::ResolveSpecialAnyTypeByConstant(core return compiler::AnyBaseType::UNDEFINED_TYPE; } +size_t EcmaRuntimeInterface::GetGlobalConstStringOffsetForAnyType(compiler::AnyBaseType type, Arch arch) const +{ + auto global_const_array_offset = + cross_values::GetJsthreadGlobalConstantsOffset(arch) + cross_values::GetGlobalConstConstantsOffset(arch); + switch (type) { + case compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::UNDEFINED_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::STRING_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_INT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::NUMBER_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::NUMBER_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_SYMBOL_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::SYMBOL_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_CALLABLE_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::FUNCTION_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::BOOLEAN_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_NULL_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::OBJECT_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_BIGINT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::BIGINT_STRING_INDEX); + case compiler::AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE: + return global_const_array_offset + panda::ecmascript::GlobalEnvConstants::GetGlobalConstantOffset( + panda::ecmascript::ConstantIndex::OBJECT_STRING_INDEX); + default: + UNREACHABLE(); + } + return 0; +} RuntimeInterface::NewObjDynInfo EcmaRuntimeInterface::GetNewObjDynInfo(uintptr_t ctor) const { static constexpr NewObjDynInfo SLOW_PATH = {NewObjDynInfo::AllocatorType::SLOW_PATH, diff --git a/runtime/compiler/ecmascript_runtime_interface.h b/runtime/compiler/ecmascript_runtime_interface.h index f81fbbeb50bed868ed16944f2fcfb3a40f3f69a6..4c04ed62ac697c4a04acffc2cbddacd6f63257c0 100644 --- a/runtime/compiler/ecmascript_runtime_interface.h +++ b/runtime/compiler/ecmascript_runtime_interface.h @@ -146,6 +146,7 @@ public: bool *is_type_profiled) override; compiler::AnyBaseType ResolveSpecialAnyTypeByConstant(coretypes::TaggedValue any_const) override; + size_t GetGlobalConstStringOffsetForAnyType(compiler::AnyBaseType type, Arch arch) const override; NewObjDynInfo GetNewObjDynInfo(uintptr_t ctor) const override; bool GetProfileDataForNamedAccess(PandaRuntimeInterface::MethodPtr m, uintptr_t slot_id, @@ -166,6 +167,11 @@ public: CleanObjectHandles(MethodCast(method)); } + uint32_t GetCallableMask() const override + { + return HClass::GetCallableMask(); + } + private: void CleanObjectHandles(Method *method); void AddObjectHandle(Method *method, ObjectHeader *obj); diff --git a/runtime/ecma_profiling.h b/runtime/ecma_profiling.h index ee8c095aab3967a66c9622de80b6993277052cf2..617b4a510c6ba447c198c9ef4ee1052b21ecb93d 100644 --- a/runtime/ecma_profiling.h +++ b/runtime/ecma_profiling.h @@ -45,11 +45,11 @@ public: stream << '['; const char *sep = ""; if (type & INTEGER) { - stream << sep << "Integer or objct array access"; + stream << sep << "Integer"; sep = "|"; } if (type & DOUBLE) { - stream << sep << "Double or not object"; + stream << sep << "Double"; sep = "|"; } if (type & BOOLEAN) { @@ -68,6 +68,65 @@ public: } }; +class ProfilingTypeOfBits { +public: + enum Type : uint8_t { + NONE = 0, + NUMBER = (1U << 0U), + SYMBOL = (1U << 1U), + BOOLEAN = (1U << 2U), + STRING = (1U << 3U), + FUNCTION = (1U << 4U), + UNDEFINED = (1U << 5U), + BIGINT = (1U << 6U), + OBJECT = (1U << 7U), + LAST = OBJECT, + }; + template + static void Dump(S &stream, Type type) + { + if (type == NONE) { + stream << "[None]"; + return; + } + stream << '['; + const char *sep = ""; + if (type & NUMBER) { + stream << sep << "Number"; + sep = "|"; + } + if (type & SYMBOL) { + stream << sep << "Symbol"; + sep = "|"; + } + if (type & BOOLEAN) { + stream << sep << "Bool"; + sep = "|"; + } + if (type & STRING) { + stream << sep << "String"; + sep = "|"; + } + if (type & OBJECT) { + stream << sep << "Object"; + sep = "|"; + } + if (type & FUNCTION) { + stream << sep << "Function"; + sep = "|"; + } + if (type & UNDEFINED) { + stream << sep << "Undefined"; + sep = "|"; + } + if (type & BIGINT) { + stream << sep << "BigInt"; + sep = "|"; + } + stream << ']'; + } +}; + class ProfilingIndexedAccessBits { public: enum Type : uint8_t { @@ -150,6 +209,7 @@ private: }; using ProfilingType = ProfileInfo; +using ProfilingTypeOf = ProfileInfo; using ProfilingIndexedAccess = ProfileInfo; inline ProfilingTypeBits::Type GetTypeFromValue(JSTaggedValue value) @@ -164,9 +224,41 @@ inline ProfilingTypeBits::Type GetTypeFromValue(JSTaggedValue value) if (value.IsBoolean()) { return ProfilingTypeBits::BOOLEAN; } + if (value.IsString()) { + return ProfilingTypeBits::STRING; + } return ProfilingTypeBits::OBJECT; } +inline ProfilingTypeOfBits::Type GetTypeOfFromValue(JSTaggedValue value) +{ + if (value.IsInt()) { + return ProfilingTypeOfBits::NUMBER; + } + // IsDouble() is encoded as `!IsInt() && !IsObject()`, IsInt() we already tested, so check only it is not an object + if (!value.IsObject()) { + return ProfilingTypeOfBits::NUMBER; + } + if (value.IsBoolean()) { + return ProfilingTypeOfBits::BOOLEAN; + } + if (value.IsString()) { + return ProfilingTypeOfBits::STRING; + } + if (value.IsBigInt()) { + return ProfilingTypeOfBits::BIGINT; + } + if (value.IsCallable()) { + return ProfilingTypeOfBits::FUNCTION; + } + if (value.IsSymbol()) { + return ProfilingTypeOfBits::SYMBOL; + } + if (value.IsUndefined()) { + return ProfilingTypeOfBits::UNDEFINED; + } + return ProfilingTypeOfBits::OBJECT; +} ProfilingIndexedAccessBits::Type GetObjectTypeFromValue(JSTaggedValue value); // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -261,6 +353,33 @@ protected: SET_LAST_FIELD_FINAL(OperandType); }; +class TypeOfOperationProfile : public ResultProfile { +public: + using Base = ResultProfile; + using Base::Base; + + ProfilingTypeOf GetOperandType() const + { + return ProfilingTypeOf(GetField()); + } + + ProfilingTypeOf GetOperandType([[maybe_unused]] size_t index) const + { + CHECK_LT(index, 1U); + return ProfilingTypeOf(GetOperandType()); + } + + static void Update(Base::ValueType *data, JSTaggedValue value) + { + *data |= OperandType::Encode(GetTypeOfFromValue(value)); + } + +protected: + using OperandType = + Base::LastField::NextField; + SET_LAST_FIELD_FINAL(OperandType); +}; + class UnaryOperationProfile : public ResultProfile { public: using Base = ResultProfile; @@ -291,9 +410,9 @@ protected: SET_LAST_FIELD_FINAL(OperandType); }; -class BinaryOperationProfile : public ResultProfile { +class BinaryOperationProfile : public ValueProfileBase { public: - using Base = ResultProfile; + using Base = ValueProfileBase; using Base::Base; ProfilingType GetOperandType(size_t index) const @@ -324,8 +443,7 @@ public: } protected: - using LeftOperandType = - Base::LastField::NextField; + using LeftOperandType = BitField; using RightOperandType = LeftOperandType::NextField; SET_LAST_FIELD_FINAL(RightOperandType); diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 8e7d4fd49c50ae1d6f3400037d1ec7274b0bfd7c..1d9a7e0c3c861ec61e5c0750a4c2a72afac93fa7 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -651,6 +651,7 @@ intrinsics: args: [acc] impl: panda::ecmascript::intrinsics::TypeofDyn clear_flags: [no_dce] + fast_path: FastTypeOfDyn - name: Callruntimerange space: ecmascript diff --git a/runtime/global_env_constants.h b/runtime/global_env_constants.h index df6b20572d414cd61351ff5e8e945977b434ff7a..ae7860fa7a2fb91d81ae173ae54014bc143642f4 100644 --- a/runtime/global_env_constants.h +++ b/runtime/global_env_constants.h @@ -381,6 +381,16 @@ public: GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET) #undef DECL_GET + static constexpr uint32_t GetConstantsOffset() + { + return MEMBER_OFFSET(GlobalEnvConstants, constants_); + } + + static constexpr uint32_t GetGlobalConstantOffset(ConstantIndex index) + { + return static_cast(index) << 3U; + } + void VisitRangeSlot(const RootRangeVisitor &visitor) { visitor(ecmascript::Root::ROOT_VM, ObjectSlot(ToUintPtr(BeginSlot())), ObjectSlot(ToUintPtr(EndSlot()))); diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index 97522c7106fe3fdb3ef860737ce1cf8ef0a2b885..4da0b2361befa9311261adb53d05fccad418f59b 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -95,6 +95,14 @@ namespace panda::ecmascript { UNUSED_VAR(rhs); \ } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define UPDATE_TYPE_OF_PROFILE(lhs) \ + if constexpr (IS_PROFILE_ENABLED) { \ + UpdateTypeOfProfile(lhs); \ + } else { \ + UNUSED_VAR(lhs); \ + } + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define UPDATE_CALL_PROFILE(func) \ if constexpr (IS_PROFILE_ENABLED) { \ @@ -976,6 +984,7 @@ public: LOG_INST() << "typeofdyn"; uint64_t acc = GetAccAsTaggedValue().GetRawData(); + UPDATE_TYPE_OF_PROFILE(acc); INTRINSIC_CALL_SETACC(intrinsics::TypeofDyn(this->GetJSThread(), acc)); this->template MoveToNextInst(); } @@ -2871,13 +2880,29 @@ public: auto prof_data = method->GetProfilingVector(); auto prof_id = this->GetInst().GetProfileId(); ASSERT(prof_id >= 0); + ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto prof_value = reinterpret_cast(&prof_data[prof_id]); - ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); return prof_value; } + void UpdateTypeOfProfile(coretypes::TaggedType value) + { + auto method = static_cast(this->GetFrame()->GetMethod()); + // Profiling is not initialized + if (method->GetProfileSize() == 0) { + return; + } + auto prof_data = method->GetProfilingVector(); + auto prof_id = this->GetInst().GetProfileId(); + ASSERT(prof_id >= 0); + ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto prof_value = reinterpret_cast(&prof_data[prof_id]); + TypeOfOperationProfile::Update(prof_value, JSTaggedValue(value)); + } + void UpdateUnaryArithProfile(coretypes::TaggedType value) { auto method = static_cast(this->GetFrame()->GetMethod()); @@ -2888,9 +2913,9 @@ public: auto prof_data = method->GetProfilingVector(); auto prof_id = this->GetInst().GetProfileId(); ASSERT(prof_id >= 0); + ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto prof_value = reinterpret_cast(&prof_data[prof_id]); - ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); UnaryOperationProfile::Update(prof_value, JSTaggedValue(value)); } @@ -2906,9 +2931,9 @@ public: auto prof_data = method->GetProfilingVector(); auto prof_id = this->GetInst().GetProfileId(); ASSERT(prof_id >= 0); + ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto prof_value = reinterpret_cast(&prof_data[prof_id]); - ASSERT(method->GetProfileSize() > helpers::ToUnsigned(prof_id)); BinaryOperationProfile::Update(prof_value, left, right); } diff --git a/tests/checked/CMakeLists.txt b/tests/checked/CMakeLists.txt index 54c0184934a1324fae017d0947264817d3bcd758..114f2e9747931cf8a6292a60eea9219851c88313 100644 --- a/tests/checked/CMakeLists.txt +++ b/tests/checked/CMakeLists.txt @@ -109,6 +109,7 @@ if (NOT PANDA_TARGET_ARM32) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/ecma_call_profile_clear.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/peephole_negoverflowandzerocheck.js SUPPORT_RELEASE true) panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/ldlex.js SUPPORT_RELEASE true) + panda_add_checked_test_ecma(FILE ${CMAKE_CURRENT_SOURCE_DIR}/typeof.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/typeof.js b/tests/checked/typeof.js new file mode 100644 index 0000000000000000000000000000000000000000..e6de10509d90ba5ebe4555d1111f1bed728800da --- /dev/null +++ b/tests/checked/typeof.js @@ -0,0 +1,140 @@ +/* + * 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. + */ + +//! CHECKER Test check TypeOfDyn +//! RUN options: "--no-async-jit=true --compiler-hotness-threshold=10 --compiler-regex _GLOBAL::test_type.*", entry: "_GLOBAL::func_main_0" +//! METHOD "test_type_undefined" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_UNDEFINED_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_UNDEFINED_TYPE" +//! METHOD "test_type_string" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_STRING_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_STRING_TYPE" +//! METHOD "test_type_boolean" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_BOOLEAN_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_BOOLEAN_TYPE" +//! METHOD "test_type_int" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE i" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_DOUBLE_TYPE" +//! METHOD "test_type_double" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_DOUBLE_TYPE i" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_DOUBLE_TYPE" +//! METHOD "test_type_bigint" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_BIGINT_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_BIGINT_TYPE" +//! METHOD "test_type_symbol" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_SYMBOL_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_SYMBOL_TYPE" +//! METHOD "test_type_function" +//! PASS_AFTER "TypesResolving" +//! INST "AnyTypeCheck ECMASCRIPT_CALLABLE_TYPE" +//! INST_NEXT "GetAnyTypeName ECMASCRIPT_CALLABLE_TYPE" +//! METHOD "test_type_object" +//! PASS_AFTER "TypesResolving" +//! INST_NOT "AnyTypeCheck ECMASCRIPT_HEAP_OBJECT_TYPE" +//! INST_NOT "GetAnyTypeName" + +//! CHECKER Test check AOT TypeOfDyn +//! RUN_PAOC options: "--compiler-regex _GLOBAL::test_type.*" +//! RUN options: "--compiler-enable-jit=false", entry: "_GLOBAL::func_main_0" + +function test_type_undefined(a) +{ + return (typeof a === "undefined"); +} + +function test_type_string(a) +{ + return (typeof a === "string"); +} + +function test_type_boolean(a) +{ + return (typeof a === "boolean"); +} + +function test_type_int(a) +{ + return (typeof a === "number"); +} + +function test_type_double(a) +{ + return (typeof a === "number"); +} + +function test_type_bigint(a) +{ + return (typeof a === "bigint"); +} + +function test_type_symbol(a) +{ + return (typeof a === "symbol"); +} + +function test_type_function(a) +{ + return (typeof a === "function"); +} + +function test_type_object(a) +{ + return (typeof a === "object"); +} +function foo () {} + +for (let i = 0 ; i < 30; i++) { + if (!test_type_undefined(undefined)) { + throw "test_type_undefined is failed "; + } + if (!test_type_string("foo")) { + throw "test_type_string is failed "; + } + if (!test_type_boolean(false)) { + throw "test_type_boolean false is failed "; + } + if (!test_type_boolean(true)) { + throw "test_type_boolean true is failed "; + } + if (!test_type_int(10)) { + throw "test_type_int is failed "; + } + if (!test_type_double(1.1)) { + throw "test_type_double is failed "; + } + if (!test_type_bigint(1n)) { + throw "test_type_bigint is failed "; + } + if (!test_type_symbol(Symbol())) { + throw "test_type_symbol is failed "; + } + if (!test_type_function(foo)) { + throw "test_type_function is failed "; + } + var obj = {}; + if (!test_type_object(obj)) { + throw "test_type_object is failed "; + } + if (!test_type_object(null)) { + throw "test_type_object null is failed "; + } +}